简体   繁体   中英

Animate collectionView layout during view controller presentation

I'm trying to present a view controller animated with a UIViewControllerAnimatedTransitioning that goes from alpha 0 to 1; and the same time animate its collection view from one layout to another. The two layouts only differ in the section inset and and line spacing.

Here is the code for moving from one layout to another:

private var useAfterLayout = false
private let layoutBefore = (
    sectionInset: UIEdgeInsets(top: 100, left: 3, bottom: 3, right: 3),
    lineSpacing: CGFloat(10.0)
)

private let layoutAfter = (
    sectionInset: UIEdgeInsets(top: 3, left: 3, bottom: 3, right: 3),
    lineSpacing: CGFloat(3.0)
)

func animateToFinalLayout() {
    useAfterLayout = true
    collectionView.performBatchUpdates({
        collectionView.collectionViewLayout.invalidateLayout()
        collectionView.setCollectionViewLayout(collectionView.collectionViewLayout, animated: true)
    }, completion: nil)
}

public func collectionView(
    _ collectionView: UICollectionView,
    layout collectionViewLayout: UICollectionViewLayout,
    insetForSectionAt section: Int
) -> UIEdgeInsets {
    useAfterLayout ? layoutAfter.sectionInset : layoutBefore.sectionInset
}

public func collectionView(
    _ collectionView: UICollectionView,
    layout collectionViewLayout: UICollectionViewLayout,
    minimumLineSpacingForSectionAt section: Int)
    -> CGFloat {
    useAfterLayout ? layoutAfter.lineSpacing : layoutBefore.lineSpacing
}

I've tried calling the animateToFinalLayout method in viewWillAppear(_:) and in animation block in the `animateTransition(using:), but the view controller just has the final layout when appearing.

UIView.animate(withDuration: animationDuration, delay: 0.0, options: .curveEaseOut, animations: {
    toView.center = transitionContext.containerView.center
    toView.alpha = 1.0
    animatedViewController?.animatePresentation()
}, completion: { didComplete in
    transitionContext.completeTransition(didComplete)
})

Putting the call in viewDidAppear(_:) animates the layout, but only after the presentation animation has finished:

How can synchronise the two animations?

As this comment suggests, using the following code makes the two animations sync perfectly.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    DispatchQueue.main.async {
        UIView.animate(withDuration: 0.35, delay: 0.0, options: .curveEaseOut, animations: {
            self.animateToFinalLayout()
        }, completion: nil)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM