У меня есть UICollectionView в моем приложении, и я хочу, чтобы он работал так же, как представление верхней части вкладки AppStore Apps, в котором прокрутка каждой ячейки делает следующую ячейку центрированной. Я каким-то образом добился этого в своем приложении без использования свойства с включенным разбиением на страницы CollectionView, выполнил некоторые вычисления размеров и получил довольно хороший результат, но иногда он отстает. Будет очень полезно, если кто-то предложит лучший подход для достижения поведения типа магазина приложений с помощью UICollectionView :).
Пример магазина приложений. Посмотрите, как работает top collectionView.
Где бы я ни находил этот тип реализации, везде он был реализован с помощью UIScrollView. Но я ищу точно такое же поведение с UICollectionView.
То, чего я достиг в своем приложении.
Посмотреть коллекцию Посмотреть внизу. Я реализовал это поведение, переопределив метод scrollViewWillEndDragging по умолчанию для scrollView, от которого наследуется UICollectionView, и в этом методе я выполнил следующие вычисления.
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// Stop scrollView sliding:
targetContentOffset.pointee = scrollView.contentOffset
let indexOfMajorCell = self.indexOfMajorCell()
// calculate conditions:
let dataSourceCount = collectionView(cardsCollectionView, numberOfItemsInSection: 0)
let swipeVelocityThreshold: CGFloat = 5.0 // after some trail and error
let hasEnoughVelocityToSlideToTheNextCell = indexOfCellBeforeDragging + 1 < dataSourceCount && velocity.x > swipeVelocityThreshold
let hasEnoughVelocityToSlideToThePreviousCell = indexOfCellBeforeDragging - 1 >= 0 && velocity.x < -swipeVelocityThreshold
let majorCellIsTheCellBeforeDragging = indexOfMajorCell == indexOfCellBeforeDragging
let didUseSwipeToSkipCell = majorCellIsTheCellBeforeDragging && (hasEnoughVelocityToSlideToTheNextCell || hasEnoughVelocityToSlideToThePreviousCell)
if didUseSwipeToSkipCell {
let snapToIndex = indexOfCellBeforeDragging + (hasEnoughVelocityToSlideToTheNextCell ? 1 : -1)
let toValue = collectionViewFlowLayout.itemSize.width * 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 {
// This is a much better way to scroll to a cell:
let indexPath = IndexPath(row: indexOfMajorCell, section: 0)
cardsCollectionView.collectionViewLayout.collectionView!.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
}
Примечание: Свойство включения разбиения по страницам UICollectionView было установлено в значение false в моей реализации, чтобы это работало. Когда я включаю это свойство в положение ВКЛ, показывалось странное поведение, когда часть каждой ячейки скрывалась всякий раз, когда я проводил пальцем по экрану.