-->

How to create a navigation transition like the App

2019-08-17 05:08发布

问题:

I found this article to create a navigation transition like the Apple news app: https://blog.rocketinsights.com/how-to-create-a-navigation-transition-like-the-apple-news-app/.

The transition is a zoom effect.

The code works great for push animation, but for pop animation (to close DetailViewController), I have a black screen instead my main viewcontroller.

As the article doesn't provide the full source code to download, I publish it on github, apply to UICollectionViewController for my needs: testZoomTransition

回答1:

I found a solution, by simplifying the source code, maybe less elegant, but effective.

Git is updated.

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let presenting = operation == .push

    // Determine which is the master view and which is the detail view that we're navigating to and from. The container view will house the views for transition animation.
    let containerView = transitionContext.containerView

    guard let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from),
        let toView = transitionContext.view(forKey: UITransitionContextViewKey.to) else {
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
            return
    }

    containerView.backgroundColor = fromView.backgroundColor

    let mainView = presenting ? fromView : toView
    let detailView = presenting ? toView : fromView

    // Determine the starting frame of the detail view for the animation. When we're presenting, the detail view will grow out of the thumbnail frame. When we're dismissing, the detail view will shrink back into that same thumbnail frame.
    let finalFrame = presenting ? detailView.frame : thumbnailFrame

    //scale factor between thumbnailFrame and size of
    let scaleFactorX = thumbnailFrame.size.width / detailView.frame.size.width
    let scaleFactorY = thumbnailFrame.size.height / detailView.frame.size.height

    if presenting {

        // Shrink the detail view for the initial frame. The detail view will be scaled to CGAffineTransformIdentity below.
        detailView.transform = CGAffineTransform(scaleX: scaleFactorX, y: scaleFactorY)
        detailView.center = CGPoint(x: thumbnailFrame.midX, y: thumbnailFrame.midY)
        detailView.clipsToBounds = true
    }


    // Set the initial state of the alpha for the master and detail views so that we can fade them in and out during the animation.
    detailView.alpha = presenting ? 0 : 1
    mainView.alpha = presenting ? 1 : 0

    // Add the view that we're transitioning to to the container view that houses the animation.
    containerView.addSubview(toView)
    containerView.bringSubview(toFront: detailView)


    // Animate the transition.
    UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 1, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: {
        // Fade the master and detail views in and out.
        detailView.alpha = presenting ? 1 : 0
        mainView.alpha = presenting ? 0 : 1

        if presenting {
            detailView.transform = CGAffineTransform.identity
            detailView.center = CGPoint(x: finalFrame.midX, y: finalFrame.midY)
        }
        else {
            detailView.transform = CGAffineTransform(scaleX: scaleFactorX, y: scaleFactorY)
            detailView.center = CGPoint(x: self.thumbnailFrame.midX, y: self.thumbnailFrame.midY)
        }


    }) { finished in
        transitionContext.completeTransition(finished)
    }
}