In this tutorial, you'll learn how to replace the push, pop and modal animations with custom transitions & percent driven interactions.
TL;DR: download the final source from gitlab
UIKit custom transition API - a theoretical lesson
There are many classes and delegates involved during the process of making a custom transition, let's walk through these items real quick, and do some coding afterwards.
Every view controller can have a transition delegate, in that delegate implementation you can provide the custom animation and interaction controllers. Those objects will be responsible for the actual animation process, and this delegate is the place where you can "inject your code" to the UIKit framework. 💉💉💉
The navigation controller delegate also has two methods that are responsible for custom push and pop animations. It's almost the same as the transitioning delegate for the view controllers, but you'll see this in action later on. 💥
The navigation controller operation is just an enum which contains the "direction" of the navigation animation. Usually push or pop.
NOTE: presenting and dismissing something modally is not exactly the same thing as pushing & popping view controllers inside a navigation stack. More on this later.
These objects are returned by the transition delegate, so basically this is the place where you implement the fancy custom view animations. 😉
This context encapsulates all the info about the transitioning, you can get the participating views, controllers and many more from this object. The transitioning context is available for you to use it during the animation.
An object that drives an interactive animation between one view controller and another.
In a nutshell, this is the thing that gives you the magical ability to swipe a navigation controller interactively back (and forth if you changed your mind) with your fingers from the edge of the screen. 📱
Custom transition animations programmatically
Let's do some real coding! I'll show you how to make a basic fade animation between view controllers inside a navigation stack. First we'll start with the push animation.
As you can see creating a custom transition animation is really simple. You just have to implement two delegate methods. One of them will return the duration of the animation, and the other will contain the actual transition.
The transition context provides a custom
containterView object that you can use in the animation, also you can grab the participating views and controllers from this object as I mentioned it before. Now let's reverse this animation. 👈
Finally you just have to implement the navigation controller's delegate method in order to replace the built-in UIKit system animations. 🛠
Note that you don't have to make two separate classes (pop & push), you can also pass the operation and implement the animations in a single animated tarnsitioning class.
Percent driven interactive transitions
So, now you know how to implement a custom transition, but it's time to make it interactive! The process is pretty simple, you'll only need a gesture recognizer and a proper delegate method to make things work. ⌨️
Inside the controller that will be popped you can take ownership of the navigation controller's delegate and implement the interactive transition controller using a left screen edge pan gesture recognizer. This whole code usually goes into a new subclass of
UIPercentDrivenInteractiveTransition but for the sake of simplicity this time we'll skip that, and go with this really easy solution. In the final example code you'll find the "subclassed version" of the interactive transition. 😅
Navigation vs modal presentation
Ok, let's cover one more thing real quick: customizing modal presentation animations for view controllers. There is a minor difference between customizing the navigation stack animations and modal presentation styles. If you want to customize a view controller transition you'd usually do something like this. 👍
Here comes the transitioning delegate, using the same objects that we already have.
If you run the code and present the modal view controller, that'll work just fine. The problem occurs when you try to dismiss the presented view controller. The whole app will turn to a black screen of death (BSOD). 🖥
(pop != dismiss) && (push != present)
You have to modify the pop animation in order to support modal dismissal animations. In short: the problem is with placing views and memory management.
The most simple solution is to introduce a new property so you can make a decision to pop or dismiss the view controller based on that flag. Now you can safely use the same animators for modally presented view controllers as well. 😬
In the custom transition example code on gitlab you'll find examples for replacing the default push & pop navigation animations with custom ones without a difference. Note that the navigation bar will always use a fade animation, unfortunately that can not be customized. Also I've made a custom modal presentation, and everything is using the interactive transitions too. Have fun! 😉
Obviously there is a lot more, but below are some links that you can follow if you hit an obstacle during your journey. Also if you don't want to manually implement custom animation effects you can use Hero the elegant transition library for iOS & tvOS.