Skip to content

Instantly share code, notes, and snippets.

@maxchuquimia
Created June 8, 2017 00:10
Show Gist options
  • Save maxchuquimia/2065319189d7c96515082856a74d4fa7 to your computer and use it in GitHub Desktop.
Save maxchuquimia/2065319189d7c96515082856a74d4fa7 to your computer and use it in GitHub Desktop.
Paging a UICollectionView when each cell is smaller than the width of the collection
// Set the inset so that the first and last cells can appear in the middle of the UICollectionView
override func layoutSubviews() {
super.layoutSubviews()
contentInset = UIEdgeInsets(top: 0, left: frame.width / 2.0 - layout.itemSize.width / 2.0, bottom: 0, right: 0)
}
private func currentCentredCell() -> UICollectionViewCell? {
return visibleCells.reduce(visibleCells.first) { (nearestCell, nextCell) -> UICollectionViewCell? in
// We need the paging to set the scrollView to show a ticket centered.
// Compare the distance between the midpoint of each cell (translated to the collectionView's coordinate space)
// with that of the cell after it. Return the cell with the nearest distance, and repeat for all visible cells
guard let cellA = nearestCell else { return nextCell }
let rectA = convert(cellA.frame, from: cellA.superview)
let rectB = convert(nextCell.frame, from: nextCell.superview)
let collectionViewMid = bounds.midX
let dxA = abs(rectA.midX - collectionViewMid)
let dxB = abs(rectB.midX - collectionViewMid)
if dxA < dxB {
return cellA
} else {
return nextCell
}
}
}
private func xOffsetFor(cell: UICollectionViewCell) -> CGFloat {
let rect = convert(cell.frame, from: cell.superview)
return rect.origin.x
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
guard let nearestCell = currentCentredCell() else { return }
guard let idx = indexPath(for: nearestCell)?.row else { return }
// Snap to the correct page according to the phyisics of the scroll
if velocity.x > 0 {
if idx + 1 < numberOfItems(inSection: 0) {
if let att = layoutAttributesForItem(at: .init(row: idx + 1, section: 0)) {
targetContentOffset.pointee.x = att.frame.origin.x - frame.width / 2.0 + att.frame.width / 2.0
return
}
}
} else if velocity.x < 0 {
if idx - 1 >= 0 {
if let att = layoutAttributesForItem(at: .init(row: idx - 1, section: 0)) {
targetContentOffset.pointee.x = att.frame.origin.x - frame.width / 2.0 - att.frame.width / 2.0
return
}
}
}
// default
let att = layoutAttributesForItem(at: .init(row: idx, section: 0))!
targetContentOffset.pointee.x = xOffsetFor(cell: nearestCell) - frame.width / 2.0 - att.frame.width / 2.0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment