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