Mark Bourke Mark Bourke - 4 months ago 25
Objective-C Question

UICollectionView to snap onto a cell when scrolling horizontally

I know some people have asked this question before but they were all about

uitableviews
or
uiscrollviews
and I couldn't get the code answered to work for me. What I would like is the snapping effect when scrolling through my
collectionview
horizontally, like what happens in the iOS app store. iOS 9 is my target build , please look at the UIKit changes before answering this,

Thank you.

Answer

Got an answer from SO post here and docs here

First What you can do is set your collection view's scrollview's delegate your class by making your class a scrollview delegate

MyViewController : SuperViewController<... ,UIScrollViewDelegate>

Then make set your view controller as the delegate

UIScrollView *scrollView = (UIScrollView *)super.self.collectionView;
scrollView.delegate = self;

Or do it in the interface builder by control + shift clicking on your collection view and then control + drag or right click drag to your view controller and select delegate. (You should know how to do this). That doesn't work. UICollectionView is a subclass of UIScrollView so you will now be able to see it in the interface builder by control + shift clicking

Next implement the delegate method - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

MyViewController.m

... 

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

}

The docs state that:

Parameters

scrollView | The scroll-view object that is decelerating the scrolling of the content view.

Discussion The scroll view calls this method when the scrolling movement comes to a halt. The decelerating property of UIScrollView controls deceleration.

Availability Available in iOS 2.0 and later.

Then inside of that method check which cell was closest to the center of the scrollview when it stopped scrolling

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
  //NSLog(@"%f", truncf(scrollView.contentOffset.x + (self.pictureCollectionView.bounds.size.width / 2)));

float visibleCenterPositionOfScrollView = scrollView.contentOffset.x + (self.pictureCollectionView.bounds.size.width / 2);

//NSLog(@"%f", truncf(visibleCenterPositionOfScrollView / imageArray.count));


NSInteger closestCellIndex;

for (id item in imageArray) {
    // equation to use to figure out closest cell
    // abs(visibleCenter - cellCenterX) <= (cellWidth + cellSpacing/2)

    // Get cell width (and cell too)
    UICollectionViewCell *cell = (UICollectionViewCell *)[self collectionView:self.pictureCollectionView cellForItemAtIndexPath:[NSIndexPath indexPathWithIndex:[imageArray indexOfObject:item]]];
    float cellWidth = cell.bounds.size.width;

    float cellCenter = cell.frame.origin.x + cellWidth / 2;

    float cellSpacing = [self collectionView:self.pictureCollectionView layout:self.pictureCollectionView.collectionViewLayout minimumInteritemSpacingForSectionAtIndex:[imageArray indexOfObject:item]];

    // Now calculate closest cell

    if (fabsf(visibleCenterPositionOfScrollView - cellCenter) <= (cellWidth + (cellSpacing / 2))) {
        closestCellIndex = [imageArray indexOfObject:item];
        break;
    }
}

if (closestCellIndex != nil) {

[self.pictureCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathWithIndex:closestCellIndex] atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];

// This code is untested. Might not work.

}
Comments