Dynamically setting layout on UICollectionView causes inexplicable contentOffset change

前端 未结 10 1637
一生所求
一生所求 2020-11-29 16:10

According to Apple\'s documentation (and touted at WWDC 2012), it is possible to set the layout on UICollectionView dynamically and even animate the changes:

10条回答
  •  长情又很酷
    2020-11-29 16:34

    I've probably spent about two weeks now trying to get various layout to transition between one another smoothly. I've found that override the proposed offset is working in iOS 10.2, but in version prior to that I still get the issue. The thing that makes my situation a bit worse is I need to transition into another layout as a result of a scroll, so the view is both scrolling and transitioning at the same time.

    Tommy's answer was the only thing that worked for me in pre 10.2 versions. I'm doing the following thing now.

    class HackedCollectionView: UICollectionView {
    
        var ignoreContentOffsetChanges = false
    
        override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
            guard ignoreContentOffsetChanges == false else { return }
            super.setContentOffset(contentOffset, animated: animated)
        }
    
        override var contentOffset: CGPoint {
            get {
                return super.contentOffset
            }
            set {
                guard ignoreContentOffsetChanges == false else { return }
                super.contentOffset = newValue
            }
        }
    
        override func setCollectionViewLayout(_ layout: UICollectionViewLayout, animated: Bool) {
            guard ignoreContentOffsetChanges == false else { return }
            super.setCollectionViewLayout(layout, animated: animated)
        }
    
        override var contentSize: CGSize {
            get {
                return super.contentSize
            }
            set {
                guard ignoreContentOffsetChanges == false else { return }
                super.contentSize = newValue
            }
        }
    
    }
    

    Then when I set the layout I do this...

    let theContentOffsetIActuallyWant = CGPoint(x: 0, y: 100)
    UIView.animate(withDuration: animationDuration,
                   delay: 0, options: animationOptions,
                   animations: {
                    collectionView.setCollectionViewLayout(layout, animated: true, completion: { completed in
                        // I'm also doing something in my layout, but this may be redundant now
                        layout.overriddenContentOffset = nil
                    })
                    collectionView.ignoreContentOffsetChanges = true
    }, completion: { _ in
        collectionView.ignoreContentOffsetChanges = false
        collectionView.setContentOffset(theContentOffsetIActuallyWant, animated: false)
    })
    

提交回复
热议问题