In the application I'm working on, there's a 320pt wide horizontal-only scrolling UICollectionView with varied content width depending on the number of items. The UICollectionViewCell subclass or itemView being used here has a width of 250pt enough to let the next itemView peak just a little bit. And I need to show one itemView at a time by snapping to the closest one.
// NOTE: This delegate method requires you to disable UICollectionView's `pagingEnabled` property.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inout CGPoint *)targetContentOffset {
CGPoint point = *targetContentOffset;
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
// This assumes that the values of `layout.sectionInset.left` and
// `layout.sectionInset.right` are the same with `layout.minimumInteritemSpacing`.
// Remember that we're trying to snap to one item at a time. So one
// visible item comprises of its width plus the left margin.
CGFloat visibleWidth = layout.minimumInteritemSpacing + layout.itemSize.width;
// It's either we go forwards or backwards.
int indexOfItemToSnap = round(point.x / visibleWidth);
// The only exemption is the last item.
if (indexOfItemToSnap + 1 == [self.collectionView numberOfItemsInSection:0]) { // last item
*targetContentOffset = CGPointMake(self.collectionView.contentSize.width -
self.collectionView.bounds.size.width, 0);
} else {
*targetContentOffset = CGPointMake(indexOfItemToSnap * visibleWidth, 0);
}
}