如何检测UIScrollView何时完成滚动
UIScrollViewDelegate有两个代理方法scrollViewDidScroll:
和scrollViewDidEndScrollingAnimation:
但这两个方法都告诉您滚动何时完成。 scrollViewDidScroll
只会通知您滚动视图确实滚动而不是滚动完成。如何检测UIScrollView何时完成滚动
另一种方法scrollViewDidEndScrollingAnimation
似乎只有在用户滚动时以编程方式移动滚动视图时才会触发。
有谁知道方案来检测滚动视图完成滚动时?
您正在查找的方法是scrollViewDidEndDragging:willDecelerate:
和scrollViewDidEndDecelerating:
。第一个通常在用户抬起手指后调用。如果它们的滚动速度足够快,导致减速,willDecelerate
将为YES
,第二种方法将在减速完成后调用。
看起来只有在减速时才起作用。如果你慢慢地平移,然后释放,它不会调用didEndDecelerating。 – 2010-11-01 23:00:33
虽然它是官方的API。它实际上并不总是像我们预期的那样工作。 @Ashley Smart提供了更实用的解决方案。 – 2011-06-14 08:45:43
我编辑了答案来澄清这个案子,肖恩。 – 2011-11-08 16:22:46
我觉得scrollViewDidEndDecelerating是你想要的。它的UIScrollViewDelegates可选方法:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
告知委托人滚动视图已结束,从而减慢滚动动作。
的320 implementations是好多了 - 这里是一个补丁来获得滚动一致的开始/结束。
-(void)scrollViewDidScroll:(UIScrollView *)sender
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
//ensure that the end of scroll is fired.
[self performSelector:@selector(scrollViewDidEndScrollingAnimation:) withObject:sender afterDelay:0.3];
...
}
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
...
}
我试过阿什利智能的答案,它的工作就像一个魅力。这是另一个想法,只使用scrollViewDidScroll
-(void)scrollViewDidScroll:(UIScrollView *)sender
{
if(self.scrollView_Result.contentOffset.x == self.scrollView_Result.frame.size.width) {
// You have reached page 1
}
}
我刚刚有两页,所以它为我工作。但是,如果您有多个页面,则可能存在问题(您可以检查当前偏移量是否为宽度的倍数,但是您不知道用户是停在第2页还是正在前往第3页或更多)
我才刚刚发现了这个问题,这是相当多的,我问是相同的: How to know exactly when a UIScrollView's scrolling has stopped?
虽然didEndDecelerating滚动时,具有固定的版本不注册平移工作。
我终于找到了解决方案。 didEndDragging具有WillDecelerate参数,在静态释放情况下为false。
通过在DidEndDragging中检查!decelerate,并结合didEndDecelerating,您将得到两种情况即滚动结束。
对于与拖动交互的所有卷轴,这将是不够的:现在
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
_isScrolling = NO;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (!decelerate) {
_isScrolling = NO;
}
}
,如果您的滚动是由于程序setContentOffset/scrollRectVisible(与animated
= YES或者你明明知道,当滚动结束):
- (void)scrollViewDidEndScrollingAnimation {
_isScrolling = NO;
}
如果您的滚动是由于其他的东西(如键盘打开或关闭键盘),好像你必须与一个黑客以检测事件,因为scrollViewDidEndScrollingAnimation
是没有用的两种。
一个分页的滚动视图的情况下:
因为,我想,苹果申请的加速曲线,scrollViewDidEndDecelerating
被调用每一个阻力,所以没有必要在这种情况下使用scrollViewDidEndDragging
。
回顾(和新手)。这并不是那么痛苦。只需添加协议,然后添加您需要检测的功能。
在包含UIScrolView的视图(类)中,添加协议,然后从这里添加任何函数到您的视图(类)。
// --------------------------------
// In the "h" file:
// --------------------------------
@interface myViewClass : UIViewController <UIScrollViewDelegate> // <-- Adding the protocol here
// Scroll view
@property (nonatomic, retain) UIScrollView *myScrollView;
@property (nonatomic, assign) BOOL isScrolling;
// Protocol functions
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView;
// --------------------------------
// In the "m" file:
// --------------------------------
@implementation BlockerViewController
- (void)viewDidLoad {
CGRect scrollRect = self.view.frame; // Same size as this view
self.myScrollView = [[UIScrollView alloc] initWithFrame:scrollRect];
self.myScrollView.delegate = self;
self.myScrollView.contentSize = CGSizeMake(scrollRect.size.width, scrollRect.size.height);
self.myScrollView.contentInset = UIEdgeInsetsMake(0.0,22.0,0.0,22.0);
// Allow dragging button to display outside the boundaries
self.myScrollView.clipsToBounds = NO;
// Prevent buttons from activating scroller:
self.myScrollView.canCancelContentTouches = NO;
self.myScrollView.delaysContentTouches = NO;
[self.myScrollView setBackgroundColor:[UIColor darkGrayColor]];
[self.view addSubview:self.myScrollView];
// Add stuff to scrollview
UIImage *myImage = [UIImage imageNamed:@"foo.png"];
[self.myScrollView addSubview:myImage];
}
// Protocol functions
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
NSLog(@"start drag");
_isScrolling = YES;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(@"end decel");
_isScrolling = NO;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSLog(@"end dragging");
if (!decelerate) {
_isScrolling = NO;
}
}
// All of the available functions are here:
// https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScrollViewDelegate_Protocol/Reference/UIScrollViewDelegate.html
这已经在一些其他的答案中进行了描述,但这里的(代码),当滚动完成如何scrollViewDidEndDecelerating
和scrollViewDidEndDragging:willDecelerate
结合执行一些操作:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self stoppedScrolling];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
willDecelerate:(BOOL)decelerate
{
if (!decelerate) {
[self stoppedScrolling];
}
}
- (void)stoppedScrolling
{
// done, do whatever
}
我有一个案子点击和拖动动作,我发现拖动调用scrollViewDidEndDecelerating
和手动更改代码([_scrollView setContentOffset:contentOffset animated:YES];);手动偏移调用scrollView DidEndScrollingAnimation。
//This delegate method is called when the dragging scrolling happens, but no when the tapping
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
//do whatever you want to happen when the scroll is done
}
//This delegate method is called when the tapping scrolling happens, but no when the dragging
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
//do whatever you want to happen when the scroll is done
}
接受的答案的斯威夫特版本:
func scrollViewDidScroll(scrollView: UIScrollView) {
// example code
}
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
// example code
}
func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView!, atScale scale: CGFloat) {
// example code
}
的UIScrollView有一个委托方法
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
添加的代码下面的线路中的委托方法
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGSize scrollview_content=scrollView.contentSize;
CGPoint scrollview_offset=scrollView.contentOffset;
CGFloat size=scrollview_content.width;
CGFloat x=scrollview_offset.x;
if ((size-self.view.frame.size.width)==x) {
//You have reached last page
}
}
如果有人需要,这里是Ashley Smart在斯威夫特回答
func scrollViewDidScroll(_ scrollView: UIScrollView) {
NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(UIScrollViewDelegate.scrollViewDidEndScrollingAnimation), with: nil, afterDelay: 0.3)
...
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
NSObject.cancelPreviousPerformRequests(withTarget: self)
...
}
刚开发的解决方案滚动成品应用范围时,检测: https://gist.github.com/k06a/731654e3168277fb1fd0e64abc7d899e
它基于的runloop模式跟踪变化的想法。至少在滚动后0.2秒后执行块。
这是用于跟踪runloop模式核心思想变化iOS10 +:对于像iOS2 +低部署目标
- (void)tick {
[[NSRunLoop mainRunLoop] performInModes:@[ UITrackingRunLoopMode ] block:^{
[self tock];
}];
}
- (void)tock {
self.runLoopModeWasUITrackingAgain = YES;
[[NSRunLoop mainRunLoop] performInModes:@[ NSDefaultRunLoopMode ] block:^{
[self tick];
}];
}
和溶液:
- (void)tick {
[[NSRunLoop mainRunLoop] performSelector:@selector(tock) target:self argument:nil order:0 modes:@[ UITrackingRunLoopMode ]];
}
- (void)tock {
self.runLoopModeWasUITrackingAgain = YES;
[[NSRunLoop mainRunLoop] performSelector:@selector(tick) target:self argument:nil order:0 modes:@[ NSDefaultRunLoopMode ]];
}
没有可被用于检测的UIScrollViewDelegate
的方法(或更好地说'预测')当滚动真的完成时:
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)
of UIScrollViewDelegate
它可以用于检测(或更好地说'预测')滚动时已经完成。
在我的情况我与水平滚动用它作为以下(在夫特3):
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
perform(#selector(self.actionOnFinishedScrolling), with: nil, afterDelay: Double(velocity.x))
}
func actionOnFinishedScrolling() {
print("scrolling is finished")
// do what you need
}
另一种方法是使用scrollViewWillEndDragging:withVelocity:targetContentOffset
被称为每当用户提起手指和包含目标内容偏移将停止滚动。在scrollViewDidScroll:
中使用此内容偏移可正确识别滚动视图何时停止滚动。
private var targetY: CGFloat?
public func scrollViewWillEndDragging(_ scrollView: UIScrollView,
withVelocity velocity: CGPoint,
targetContentOffset: UnsafeMutablePointer<CGPoint>) {
targetY = targetContentOffset.pointee.y
}
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.y == targetY) {
print("finished scrolling")
}
也看,如果你想通过程序滚动后,检测成品滚动:http://stackoverflow.com/questions/2358046/is-it-possible-to-be-notified-when-a-uitableview-完成滚动 – Trevor 2011-07-07 02:53:36