I would like to add and sync the rotation transition effect while scrolling through the collection view, so far I managed to complete the following by resizing, add fading effect & snapping of the collection view cell when it's near to the center of the scroll view.
The expected result should be like this:
Effect of fading the collection view while scrolling:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// When the cell is at the center it has it's the original size
// When the cell is moving left | right make it smaller by multiplying its size with a smaller scale
// The scale is determined by the distance from the center of the cell to the center of the collection view
let centerX = collectionView.center.x
for (index, cell) in collectionView.visibleCells.enumerated() {
// Coordinate of the cell in the viewcontroller's root view coordinate space
let cell = cell as! PlayerMixerCollectionCell
let basePosition = cell.convert(CGPoint.zero, to: self.view)
let cellCenterX = basePosition.x + collectionView.frame.size.height / 2.0
let tolerance = 0.02
let distance = abs(cellCenterX - centerX)
var scale = 1.0 + tolerance - (Double(( distance / centerX )) * 0.105)
// Set maximum scale for centered item
if (scale > 1.0) {
scale = 1.0
}
// Set minimum scale so the previous and next item will have the same size
if (scale < 0.860091) {
scale = 0.860091
}
if (scale > 0.860091 && scale < 1.0) {
// Transform the previous and next item cell size based on the scale
cell.setItemAsInactive(withScale: CGFloat(scale))
} else {
// Transform the centered item cell size based on the scale
cell.setItemAsActive(withScale: CGFloat(scale))
}
}
}
Snapping to the nearest collection view cell and position it at the center:
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
// Stop scrolling to this point
targetContentOffset.pointee = collectionView.contentOffset
// Calculate conditions
let indexOfMajorItem = determineIndexOfMajorItem()
let itemCount = cells.count - 1
let swipeVelocityThreshold: CGFloat = 0.5
let hasEnoughVelocityToSlideToNextItem = indexOfCellBeforeDragging + 1 < itemCount && velocity.x > swipeVelocityThreshold
let hasEnoughVelocityToSlideToPrevItem = indexOfCellBeforeDragging - 1 >= 0 && velocity.x < -swipeVelocityThreshold
let isMajorItemMatchPrevItem = indexOfMajorItem == indexOfCellBeforeDragging
let didSwipeToSkipItem = isMajorItemMatchPrevItem && (hasEnoughVelocityToSlideToNextItem || hasEnoughVelocityToSlideToPrevItem)
// If possible animate so that swipe animation continues or pop back to the expected item
let snappedItemIndex = didSwipeToSkipItem ? indexOfCellBeforeDragging + (hasEnoughVelocityToSlideToNextItem ? 1 : -1) : indexOfMajorItem
let snappedItemIndexPath = IndexPath(item: snappedItemIndex, section: 0)
indexOfCenteredCell = snappedItemIndexPath
// Scroll to the snapped item
collectionView.scrollToItem(at: snappedItemIndexPath, at: .centeredHorizontally, animated: true)
}