I\'m working on some ticker-like functionality and am using a UICollectionView
. It was originally a scrollView, but we figure a collectionView will make it easier
If you need to start animation before user start dragging UICollectionView (e.g. from one page to another page), you can use this workaround to preload side cells:
func scroll(to index: Int, progress: CGFloat = 0) {
let isInsideAnimation = UIView.inheritedAnimationDuration > 0
if isInsideAnimation {
// workaround
// preload left & right cells
// without this, some cells will be immediately removed before animation starts
preloadSideCells()
}
collectionView.contentOffset.x = (CGFloat(index) + progress) * collectionView.bounds.width
if isInsideAnimation {
// workaround
// sometimes invisible cells not removed (because of side cells preloading)
// without this, some invisible cells will persists on superview after animation ends
removeInvisibleCells()
UIView.performWithoutAnimation {
self.collectionView.layoutIfNeeded()
}
}
}
private func preloadSideCells() {
collectionView.contentOffset.x -= 0.5
collectionView.layoutIfNeeded()
collectionView.contentOffset.x += 1
collectionView.layoutIfNeeded()
}
private func removeInvisibleCells() {
let visibleCells = collectionView.visibleCells
let visibleRect = CGRect(
x: max(0, collectionView.contentOffset.x - collectionView.bounds.width),
y: collectionView.contentOffset.y,
width: collectionView.bounds.width * 3,
height: collectionView.bounds.height
)
for cell in visibleCells {
if !visibleRect.intersects(cell.frame) {
cell.removeFromSuperview()
}
}
}
Without this workaround, UICollectionView will remove cells, that not intersects target bounds, before the animation starts.
P.S. This working only if you need animate to next or previous page.