I need to show 3 items in a UICollectionView, with paging enabled like this
@raheel-sadiq answer is great but pretty hard to understand, I think. Here's a much readable version, in my opinion:
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint,
targetContentOffset: UnsafeMutablePointer) {
//minimumLineSpacing and insetForSection are two constants in my code
//this cell width is for my case, adapt to yours
let cellItemWidth = view.frame.width - (insetForSection.left + insetForSection.right)
let pageWidth = Float(cellItemWidth + minimumLineSpacing)
let offsetXAfterDragging = Float(scrollView.contentOffset.x)
let targetOffsetX = Float(targetContentOffset.pointee.x)
let pagesCountForOffset = pagesCount(forOffset: offsetXAfterDragging, withTargetOffset: targetOffsetX, pageWidth: pageWidth)
var newTargetOffsetX = pagesCountForOffset * pageWidth
keepNewTargetInBounds(&newTargetOffsetX, scrollView)
//ignore target
targetContentOffset.pointee.x = CGFloat(offsetXAfterDragging)
let newTargetPoint = CGPoint(x: CGFloat(newTargetOffsetX), y: scrollView.contentOffset.y)
scrollView.setContentOffset(newTargetPoint, animated: true)
//if you're using pageControl
pageControl.currentPage = Int(newTargetOffsetX / pageWidth)
}
fileprivate func pagesCount(forOffset offset: Float, withTargetOffset targetOffset: Float, pageWidth: Float) -> Float {
let isRightDirection = targetOffset > offset
let roundFunction = isRightDirection ? ceilf : floorf
let pagesCountForOffset = roundFunction(offset / pageWidth)
return pagesCountForOffset
}
fileprivate func keepNewTargetInBounds(_ newTargetOffsetX: inout Float, _ scrollView: UIScrollView) {
if newTargetOffsetX < 0 { newTargetOffsetX = 0 }
let contentSizeWidth = Float(scrollView.contentSize.width)
if newTargetOffsetX > contentSizeWidth { newTargetOffsetX = contentSizeWidth }
}