Paging UICollectionView by cells, not screen Paging UICollectionView by cells, not screen ios ios

Paging UICollectionView by cells, not screen


just override the method:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {    *targetContentOffset = scrollView.contentOffset; // set acceleration to 0.0    float pageWidth = (float)self.articlesCollectionView.bounds.size.width;    int minSpace = 10;    int cellToSwipe = (scrollView.contentOffset.x)/(pageWidth + minSpace) + 0.5; // cell width + min spacing for lines    if (cellToSwipe < 0) {        cellToSwipe = 0;    } else if (cellToSwipe >= self.articles.count) {        cellToSwipe = self.articles.count - 1;    }    [self.articlesCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:cellToSwipe inSection:0] atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];}


Horizontal Paging With Custom Page Width (Swift 4 & 5)

Many solutions presented here result in some weird behaviour that doesn't feel like properly implemented paging.


The solution presented in this tutorial, however, doesn't seem to have any issues. It just feels like a perfectly working paging algorithm. You can implement it in 5 simple steps:

  1. Add the following property to your type: private var indexOfCellBeforeDragging = 0
  2. Set the collectionView delegate like this: collectionView.delegate = self
  3. Add conformance to UICollectionViewDelegate via an extension: extension YourType: UICollectionViewDelegate { }
  4. Add the following method to the extension implementing the UICollectionViewDelegate conformance and set a value for pageWidth:

    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {    let pageWidth = // The width your page should have (plus a possible margin)    let proportionalOffset = collectionView.contentOffset.x / pageWidth    indexOfCellBeforeDragging = Int(round(proportionalOffset))}
  5. Add the following method to the extension implementing the UICollectionViewDelegate conformance, set the same value for pageWidth (you may also store this value at a central place) and set a value for collectionViewItemCount:

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {    // Stop scrolling    targetContentOffset.pointee = scrollView.contentOffset    // Calculate conditions    let pageWidth = // The width your page should have (plus a possible margin)    let collectionViewItemCount = // The number of items in this section    let proportionalOffset = collectionView.contentOffset.x / pageWidth    let indexOfMajorCell = Int(round(proportionalOffset))    let swipeVelocityThreshold: CGFloat = 0.5    let hasEnoughVelocityToSlideToTheNextCell = indexOfCellBeforeDragging + 1 < collectionViewItemCount && velocity.x > swipeVelocityThreshold    let hasEnoughVelocityToSlideToThePreviousCell = indexOfCellBeforeDragging - 1 >= 0 && velocity.x < -swipeVelocityThreshold    let majorCellIsTheCellBeforeDragging = indexOfMajorCell == indexOfCellBeforeDragging    let didUseSwipeToSkipCell = majorCellIsTheCellBeforeDragging && (hasEnoughVelocityToSlideToTheNextCell || hasEnoughVelocityToSlideToThePreviousCell)    if didUseSwipeToSkipCell {        // Animate so that swipe is just continued        let snapToIndex = indexOfCellBeforeDragging + (hasEnoughVelocityToSlideToTheNextCell ? 1 : -1)        let toValue = pageWidth * CGFloat(snapToIndex)        UIView.animate(            withDuration: 0.3,            delay: 0,            usingSpringWithDamping: 1,            initialSpringVelocity: velocity.x,            options: .allowUserInteraction,            animations: {                scrollView.contentOffset = CGPoint(x: toValue, y: 0)                scrollView.layoutIfNeeded()            },            completion: nil        )    } else {        // Pop back (against velocity)        let indexPath = IndexPath(row: indexOfMajorCell, section: 0)        collectionView.scrollToItem(at: indexPath, at: .left, animated: true)    }}