如何创建像 Apple 新闻应用程序那样的导航过渡?

How to create a navigation transition like the Apple news app?

我发现这篇文章可以像 Apple 新闻应用程序一样创建导航转换:https://blog.rocketinsights.com/how-to-create-a-navigation-transition-like-the-apple-news-app/

过渡是缩放效果。

该代码非常适合推送动画,但对于弹出动画(关闭 DetailViewController),我有一个黑屏而不是我的主屏幕 viewcontroller。

由于文章没有提供完整的源码下载,所以我发布在github,申请UICollectionViewController满足我的需求:testZoomTransition

我找到了一个解决方案,通过简化源代码,可能不太优雅,但有效。

Git 已更新。

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)
    }
}