UICollectionView: how to detect when scrolling has

2019-03-08 23:21发布

问题:

I'm using a UICollectionView to scroll through a set of thumbnails quickly. Once scrolling ends, I'd like to display a larger hi-res version of the current thumbnail.

How can I detect when the user has completed scrolling? I do implement didEndDisplayingCell, but that only tells me when a particular cell has scrolled off; it doesn't tell me when the scroll motion actually completes.

回答1:

NS_CLASS_AVAILABLE_IOS(6_0) @interface UICollectionView : UIScrollView

UICollectionView is a subclass of UIScrollView. So if you have set the delegate and implemented UIScrollViewDelegate, you should be able to detect this the same way as UIScrollView.

For eg:-

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

As per documentation, the above method should tell when the scroll view has ended decelerating the scrolling movement.



回答2:

Just to cover your bases you should implement both these UIScrollViewDelegate methods. In some cases there may not be a deceleration (and scrollViewDidEndDecelerating would not be called), for e.g., the page is fully scrolled in place. In those case do your update right there in scrollViewDidEndDragging.

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

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


回答3:

An important fact to note here :

This method gets called on User initiated scrolls (i.e a Pan gesture)

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;

On the other hand, this one gets called on all manually (programatically) initiated scrolls (like scrollRectToVisible or scrollToItemAtIndexPath)

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView


回答4:

Swift 3 version:

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    // Your code here
}


回答5:

Swift 3 version of Abey M and D6mi 's answers:

When scroll is caused by user action

public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if (!decelerate) {
        //cause by user
        print("SCROLL scrollViewDidEndDragging")
    }
}

public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    //caused by user
    print("SCROLL scrollViewDidEndDecelerating")
}

When scroll is caused by code action (programmatically): (like "scrollRectToVisible" or "scrollToItemAtIndexPath")

public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
    //caused by code
    print("SCROLL scrollViewDidEndScrollingAnimation")
}

Notes:

  • Put these functions in your UIScrollViewDelegate or UICollectionViewDelegate delegate.
  • if you don't have a separate delegate, make your current class extend a UIScrollViewDelegate op top of your class file

.

open class MyClass: NSObject , UICollectionViewDelegate

and somewhere in your viewWillAppear make the class its own delegate

override open func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // ...
    self.myScrollView.delegate = self
    // ...
}


回答6:

if you want to use the visible indexpath:

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


    if([self.collectionView indexPathsForVisibleSupplementaryElementsOfKind:UICollectionElementKindSectionHeader]){
        NSIndexPath *firstVisibleIndexPath = [[self.collectionView indexPathsForVisibleSupplementaryElementsOfKind:UICollectionElementKindSectionHeader] firstObject];
        [self.collectionView scrollToItemAtIndexPath:firstVisibleIndexPath atScrollPosition:UICollectionViewScrollPositionTop animated:YES];
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
    }
}