2009-06-14 61 views
119

UIScrollViewDelegate有兩個代理方法scrollViewDidScroll:scrollViewDidEndScrollingAnimation:但這兩個方法都告訴您滾動何時完成。 scrollViewDidScroll只會通知您滾動視圖確實滾動而不是滾動完成。如何檢測UIScrollView何時完成滾動

另一種方法scrollViewDidEndScrollingAnimation似乎只有在用戶滾動時以編程方式移動滾動視圖時纔會觸發。

有誰知道方案來檢測滾動視圖完成滾動時?

+0

也看,如果你想通過程序滾動後,檢測成品滾動:http://stackoverflow.com/questions/2358046/is-it-possible-to-be-notified-when-a-uitableview-完成滾動 – Trevor 2011-07-07 02:53:36

回答

127

您正在查找的方法是scrollViewDidEndDragging:willDecelerate:scrollViewDidEndDecelerating:。第一個通常在用戶擡起手指後調用。如果它們的滾動速度足夠快,導致減速,willDecelerate將爲YES,第二種方法將在減速完成後調用。

From the UIScrollViewDelegate docs.

+10

看起來只有在減速時才起作用。如果你慢慢地平移,然後釋放,它不會調用didEndDecelerating。 – 2010-11-01 23:00:33

+3

雖然它是官方的API。它實際上並不總是像我們預期的那樣工作。 @Ashley Smart提供了更實用的解決方案。 – 2011-06-14 08:45:43

+0

我編輯了答案來澄清這個案子,肖恩。 – 2011-11-08 16:22:46

21

我覺得scrollViewDidEndDecelerating是你想要的。它的UIScrollViewDelegates可選方法:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 

告知委託人滾動視圖已結束,從而減慢滾動動作。

UIScrollViewDelegate documentation

155

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]; 
... 
} 
3

我試過阿什利智能的答案,它的工作就像一個魅力。這是另一個想法,只使用scrollViewDidScroll

-(void)scrollViewDidScroll:(UIScrollView *)sender 
{ 
    if(self.scrollView_Result.contentOffset.x == self.scrollView_Result.frame.size.width)  { 
    // You have reached page 1 
    } 
} 

我剛剛有兩頁,所以它爲我工作。但是,如果您有多個頁面,則可能存在問題(您可以檢查當前偏移量是否爲寬度的倍數,但是您不知道用戶是停在第2頁還是正在前往第3頁或更多)

7

我纔剛剛發現了這個問題,這是相當多的,我問是相同的: How to know exactly when a UIScrollView's scrolling has stopped?

雖然didEndDecelerating滾動時,具有固定的版本不註冊平移工作。

我終於找到了解決方案。 didEndDragging具有WillDecelerate參數,在靜態釋放情況下爲false。

通過在DidEndDragging中檢查!decelerate,並結合didEndDecelerating,您將得到兩種情況即滾動結束。

18

對於與拖動交互的所有卷軸,這將是不夠的:現在

- (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

1

回顧(和新手)。這並不是那麼痛苦。只需添加協議,然後添加您需要檢測的功能。

在包含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 
16

這已經在一些其他的答案中進行了描述,但這裏的(代碼),當滾動完成如何scrollViewDidEndDeceleratingscrollViewDidEndDragging:willDecelerate結合執行一些操作:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 
{ 
    [self stoppedScrolling]; 
} 

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
        willDecelerate:(BOOL)decelerate 
{ 
    if (!decelerate) { 
     [self stoppedScrolling]; 
    } 
} 

- (void)stoppedScrolling 
{ 
    // done, do whatever 
} 
1

我有一個案子點擊和拖動動作,我發現拖動調用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 
} 
2

接受的答案的斯威夫特版本:

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 
} 
0

的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 
} 
} 
1

如果有人需要,這裏是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) 
    ... 
} 
2

剛開發的解決方案滾動成品應用範圍時,檢測: 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 ]]; 
} 
0

沒有可被用於檢測的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 
} 
1

另一種方法是使用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") 
    }