Прокрутка и разбивка на страницы в UICollectionView
Это логика привязки для представления коллекции с ячейками одинакового размера и одним разделом (можно легко добавить логику для большего количества разделов).
scrollViewWillEndDragging имеет параметр inout targetContentOffset, что означает, что мы можем читать и изменять конечную позицию прокрутки. К счастью, нам не нужно учитывать вставки, интервалы между строками или элементами (потеряли много времени, включив их, а затем не смогли понять, почему правильная математика дает неправильные результаты), но нам действительно необходимо рассмотреть случай, когда пользователь прокручивает последнюю страницу - targetContentOffset будет в пределах границ, а текущий contentOffset - нет, поэтому нам нужно также проверьте это:
// Get our cell width let cellWidth = collectionView( collectionView, layout: collectionView.collectionViewLayout, sizeForItemAtIndexPath: NSIndexPath(forItem: 0, inSection: 0) ).width let page: CGFloat // Calculate the proposed "page" let proposedPage = targetContentOffset.memory.x / cellWidth // 3.25 should return page 3: floor(3.95) == floor(3) // 3.3+ should return page 4: floor(4.0+) != floor(3) if floor(proposedPage + 0.7) == floor(proposedPage) && scrollView.contentOffset.x <= targetContentOffset.memory.x { page = floor(proposedPage) } else { page = floor(proposedPage + 1) } // Replace the end position of the scroll targetContentOffset.memory = CGPoint( x: cellWidth * page, y: targetContentOffset.memory.y )
Если требуется «истинная» разбивка на страницы, например, при прокрутке по одной странице за раз, нам нужно немного изменить:
// We need to save the starting point private var startingScrollingOffset = CGPoint.zero func scrollViewWillBeginDragging(scrollView: UIScrollView) { startingScrollingOffset = scrollView.contentOffset } func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { // [...] // First, we use the current contentOffset // instead of the target one let proposedPage = scrollView.contentOffset.x / cellWidth // If we scroll forward, we need to pass 10% of a page: // floor(3.1 + 0.9) != floor(3) // If we scroll backwards, we need to reach below 90% // of the previous one: floor(2.89 + 0.1) == floor(2) let delta: CGFloat = scrollView.contentOffset.x > startingScrollingOffset.x ? 0.9 : 0.1 // Then, instead of using a flat value, we use the delta value, // and we also remove the targetContentOffset logic if floor(proposedPage + delta) == floor(proposedPage) { // [...] }
Хотя процентные значения были выбраны случайным образом, 0,1 кажется немного лучше для истинной разбивки на страницы, а 0,3 - лучше для мгновенной прокрутки.
Вы можете найти больше подобных статей в моем блоге или подписаться на мою ежемесячную рассылку новостей. Первоначально опубликовано на rolandleth.com.