Created
June 8, 2017 00:10
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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