How do you build a custom view controller transition, including an interactive one?
Predict first
Does this minimal animator compile?
import UIKit
final class FadeAnimator: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using ctx: UIViewControllerContextTransitioning?) -> TimeInterval { 0.3 }
func animateTransition(using ctx: UIViewControllerContextTransitioning) {
guard let to = ctx.view(forKey: .to) else { return ctx.completeTransition(false) }
ctx.containerView.addSubview(to)
to.alpha = 0
UIView.animate(withDuration: 0.3, animations: { to.alpha = 1 }) { _ in
ctx.completeTransition(!ctx.transitionWasCancelled)
}
}
}
- Yes
- No
Mental model. The animator is a choreographer given the dancers (the two views) and the stage (the container). They must always finish by announcing “the scene is over”.
A transition has three roles. A transitioning delegate (UIViewControllerTransitioningDelegate for modals, UINavigationControllerDelegate for push and pop) is asked for the animator. An animator (UIViewControllerAnimatedTransitioning) provides transitionDuration and animateTransition(using:). Inside it you receive a UIViewControllerContextTransitioning object: take the containerView, fetch the viewController(forKey:) for from and to, add the incoming view to the container, run your animation, and always call transitionContext.completeTransition(!transitionContext.transitionWasCancelled), or the UI freezes.
For interactive transitions, also return a UIViewControllerInteractiveTransitioning, typically a UIPercentDrivenInteractiveTransition, and drive it from a gesture: update(_:) with the progress, then finish() or cancel(). To change the chrome around a modal (a dimming view, a custom frame) subclass UIPresentationController. Newer SDKs add built-in zoom transitions (preferredTransition = .zoom(...)) that replace most hand-written ones. Pitfalls: not completing the transition, leaving the “from” view in the container, animating with Auto Layout instead of explicit frames or transforms, and ignoring cancellation.
Two methods are required: the duration and the animation. It ends by completing the transition, which is what releases the UI.
Common traps
- Not calling
completeTransition. The screen hangs, with the old view stuck in the container. - Ignoring a cancelled interactive transition. Pass the right success flag, or the hierarchy ends up wrong.
They might follow up with
- When do you need a
UIPresentationController? When the presented view is not full screen and needs its own surrounding views, such as a dimmed background. - How do you drive one with a pan gesture? Create the interactive transition when the gesture begins and update it with the translation.
Related questions
- 7.3.3 How does modal presentation work, and how do the presentation styles and sheets differ?
- 7.3.1 What is the view controller lifecycle, and what belongs in each method?
← How does modal presentation work, and how do the presentation styles…