Hello! Welcome to the final lesson in our module on "Interactive Animations and Transitions."
In our last lesson, we dove into CAShapeLayer and CABasicAnimation, learning how to create sophisticated line-drawing effects by animating the strokeEnd property. This gave you fine-grained control over animating vector shapes.
Today, we'll use our animation skills in a broader context. Our goal is to implement a custom view controller transition using the UIViewControllerAnimatedTransitioning protocol. This is a hallmark of a polished, professional iOS app, allowing you to move beyond the standard "slide up" or "push" transitions to create unique, branded experiences that guide and delight the user.
1. The Anatomy of a Custom Transition
Before we write any code, it's crucial to understand the main components that UIKit uses to manage a custom view controller transition. When you present one view controller from another, a negotiation happens behind the scenes.
Here are the key players:
- The Transitioning Delegate (
UIViewControllerTransitioningDelegate): An object you provide that acts as a factory. Its job is to supply the system with the custom "animator" object that will perform the transition. - The Animation Controller (
UIViewControllerAnimatedTransitioning): This is the object that does the actual work. You implement its methods to define the duration of the transition and, most importantly, the animations themselves. - The Transitioning Context (
UIViewControllerContextTransitioning): The system creates this object and passes it to your animation controller. It's a treasure trove of information, giving you access to the "from" and "to" view controllers, their views, and the all-important container view. - The Container View: This is a temporary view, provided by the context, that serves as the stage for your animation. All transition animations take place within this view's coordinate space.
The following diagram illustrates how these components interact.

To solidify the concept of the container view, take a moment to read this brief explanation.
Custom UIViewController transitions in Swift | by Tung Fam - Medium
The article "Custom UIViewController transitions in Swift" provides a great, simple explanation of the container view's role.
Please read the short section titled "Some theory 🤓". Focus on how it describes the Transition Container View as a temporary view that exists for the duration of the animation.
With this theoretical foundation, we're ready to build a custom transition from scratch.
2. Implementing a Custom Presentation and Dismissal
We'll now walk through the process of creating a custom transition that scales a view controller into view with a spring effect and dismisses it with a more complex keyframe animation. The following video tutorial is an excellent, practical guide that covers all the necessary steps.
Custom View Controller Transitions
We'll be following the "Custom View Controller Transitions" video from Code Pro. It provides a clear, step-by-step implementation of both a presentation and dismissal animation.
First, watch from the beginning up to 04:27. This part introduces the goal and shows how to create the AnimationController class, conform it to NSObject and UIViewControllerAnimatedTransitioning, and stub out the required methods (transitionDuration and animateTransition).
The Animator Object
As you saw in the video, the first step is creating our animator class. This class, which the video calls AnimationController, will conform to UIViewControllerAnimatedTransitioning. It has two essential methods:
transitionDuration(using:): Here, you return the total duration of your animation in seconds.animateTransition(using:): This is where the magic happens. You receive thetransitionContextand use it to orchestrate the animation.
Implementing the "Present" Animation
Now, let's focus on the presentation animation. The process follows a clear pattern:
- Get a reference to the views and view controllers from the
transitionContext. You'll need thecontainerView, thetoview controller (the one being presented), and sometimes thefromview controller. - Add the
toview controller's view to thecontainerView. This is a critical step; without it, the view you want to show won't be in the view hierarchy. - Set the initial state of the
toview. For a scaling animation, this means setting its transform to be scaled down to zero. - Animate to the final state inside a
UIView.animateblock. Here, you reset the transform to the identity (normal size). - Call
completeTransition()in the animation's completion handler to signal to UIKit that the transition is finished.
Let's watch this process in action.
Custom View Controller Transitions
Let's continue with the video.
Watch from 04:27 to 20:05. This long segment covers two key parts: Implementing presentAnimation (04:27 - 17:16): Pay close attention to how the transitionContext is used to get the views, how the toView is added to the containerView, and how the transform property is animated. Notice the call to transitionContext.completeTransition(true) in the completion block. Wiring up the transitioningDelegate (17:16 - 20:05): See how the presented view controller conforms to UIViewControllerTransitioningDelegate and returns an instance of our AnimationController from the animationController(forPresented:...) method. The transitioningDelegate property must also be set.
The Importance of clipsToBounds
The video makes an excellent point about a subtle visual artifact that can occur during scaling animations.
Custom View Controller Transitions
Now, let's see a quick but important demonstration.
Watch the segment from 20:05 to 22:09. This explains why setting clipsToBounds = true on the animating view is important to prevent its content from 'spilling out' during the scaling effect.
This is a great example of the attention to detail required for professional-level animations.
Implementing the "Dismiss" Animation with Keyframes
Dismissal follows a similar pattern, but with the roles reversed: the view being dismissed is the from view. For our dismissal animation, we'll use UIView.animateKeyframes to create a multi-stage animation: first scaling down, then moving off-screen while fading out.
This demonstrates how you can compose more complex sequences than a simple UIView.animate block allows.
Custom View Controller Transitions
Let's implement the dismissal animation.
Finally, watch from 22:09 to the end (33:59). This section covers: Implementing dismissAnimation (22:09 - 30:54): Focus on the use of UIView.animateKeyframes to chain multiple animations (scaling, translation, and alpha). Also, note how the animationController(forDismissed:...) delegate method is implemented. The Black Screen Problem (30:54 - 33:59): This is a crucial professional tip. When dismissing, you must add the toView (the view controller you are returning to) to the containerView behind the fromView to prevent a black screen during the animation. Pay close attention to this explanation.
The logic for handling the dismissal transition's container view is a common source of bugs for developers new to this topic. Ensuring the toView is present provides visual continuity and prevents the jarring appearance of a black void.
3. Summary of the Transition Process
You've just seen a complete, end-to-end implementation of a custom view controller transition. Let's recap the essential steps, which are also summarized well in the LINK resource.
- Set the Delegate: Set the
transitioningDelegateproperty on the view controller you are about to present. - Conform to the Delegate Protocol: The delegate object must conform to
UIViewControllerTransitioningDelegate. - Provide Animators: Implement
animationController(forPresented:...)andanimationController(forDismissed:...)to return your custom animator object. - Create the Animator: Your animator class must conform to
UIViewControllerAnimatedTransitioning. - Implement
transitionDuration(using:): Return the animation duration. - Implement
animateTransition(using:):- Get the
containerView,fromView, andtoViewfrom the context. - Add the necessary views to the
containerView. - Set the initial state of the views.
- Use
UIView.animateorUIView.animateKeyframesto perform the animation. - In the animation's completion block, remove any temporary views and call
transitionContext.completeTransition(!wasCancelled).
- Get the
Conclusion
Mastering custom view controller transitions is a significant step toward building truly unique and high-quality apps. You now have the power to define exactly how users navigate between different parts of your application, creating an experience that is both functional and memorable.
Key Takeaways:
- Custom transitions are managed by a
transitioningDelegatethat vends ananimationController. - The animation controller conforms to
UIViewControllerAnimatedTransitioningand performs the animation within thecontainerViewprovided by thetransitionContext. - The core steps are: add the
toView, set initial properties, animate to final properties, and callcompleteTransition(). - For dismissals, remember to add the
toViewto the container to avoid showing a black background.
As a final thought on professionalism, the approach we took today is great for a specific transition. In larger apps, you might create a dedicated manager class (like the ModalTransitionManager described in the article "Mastering view controller transitions, part 1: Make them reusable") to handle vending animators. This makes your transition logic more reusable and decoupled from your view controllers, a key principle of clean architecture.
Preview of the Next Lesson:
We have now learned to build complex, interactive, and custom animations. But with great power comes great responsibility! A beautiful animation that stutters or drops frames can be worse than no animation at all.
In our next module, we will shift our focus to performance. In the first lesson, you will learn how to profile rendering performance and identify dropped frames using the Core Animation instrument in Xcode's Instruments tool. This will give you the skills to ensure your animations are as smooth and efficient as they are beautiful.