Animating UICollectionView contentOffset does not display non-visible cells

后端 未结 7 2106
旧巷少年郎
旧巷少年郎 2021-02-01 18:31

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

7条回答
  •  一生所求
    2021-02-01 19:08

    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.

提交回复
热议问题