UICollectionView: how to detect when scrolling has stopped

IosObjective CIos6Uicollectionview

Ios Problem Overview


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.

Ios Solutions


Solution 1 - Ios

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.

Solution 2 - Ios

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

Solution 3 - Ios

An important fact to note here.

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

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

or in Swift:

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)


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

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView

or in Swift:

func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView)

Solution 4 - Ios

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
    // ...
}

Solution 5 - Ios

Swift 3 version:

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

Solution 6 - Ios

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGeorge ArmholdView Question on Stackoverflow
Solution 1 - IosiDevView Answer on Stackoverflow
Solution 2 - IosAbey MView Answer on Stackoverflow
Solution 3 - IosD6miView Answer on Stackoverflow
Solution 4 - IosdrpaweloView Answer on Stackoverflow
Solution 5 - IosMr StanevView Answer on Stackoverflow
Solution 6 - IosOfir MalachiView Answer on Stackoverflow