Dynamically setting layout on UICollectionView causes inexplicable contentOffset change

前端 未结 10 1621
一生所求
一生所求 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:33

    2019 actual solution

    Say you have a number of layouts for your "Cars" view.

    Let's say you have three.

    CarsLayout1: UICollectionViewLayout { ...
    CarsLayout2: UICollectionViewLayout { ...
    CarsLayout3: UICollectionViewLayout { ...
    

    It will jump when you animate between layouts.

    It's just an undeniable mistake by Apple. It jumps when you animate, without question.

    The fix is this:

    You must have a global float, and, the following base class:

    var avoidAppleMessupCarsLayouts: CGPoint? = nil
    
    class FixerForCarsLayouts: UICollectionViewLayout {
        
        override func prepareForTransition(from oldLayout: UICollectionViewLayout) {
            avoidAppleMessupCarsLayouts = collectionView?.contentOffset
        }
        
        override func targetContentOffset(
            forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
            if avoidAppleMessupCarsLayouts != nil {
                return avoidAppleMessupCarsLayouts!
            }
            return super.targetContentOffset(forProposedContentOffset: proposedContentOffset)
        }
    }
    

    So here are the three layouts for your "Cars" screen:

    CarsLayout1: FixerForCarsLayouts { ...
    CarsLayout2: FixerForCarsLayouts { ...
    CarsLayout3: FixerForCarsLayouts { ...
    

    That's it. It now works.


    1. Incredibly obscurely, you could have different "sets" of layouts (for Cars, Dogs, Houses, etc.), which could (conceivably) collide. For this reason, have a global and a base class as above for each "set".

    2. This was invented by passing user @Isaacliu, above, many years ago.

    3. A detail, FWIW in Isaacliu's code fragment, finalizeLayoutTransition is added. In fact it's not necessary logically.

    The fact is, until Apple change how it works, every time you animate between collection view layouts, you do have to do this. That's life!

提交回复
热议问题