A few weeks ago, I wrote this post about the storyboard’s features introduced in iOS 9. In that post, I mentioned that you can now trigger a custom view controller transition through storyboard segues. Starting from iOS 9, you can perform view controller transitions using the new APIs introduced by Apple first in iOS 7 and, then slightly modified in iOS 8. These APIs use dedicated objects to control the transition animations. In this post, I am going to show you how to use these APIs and trigger these animations from the storyboard.

Mastering view controller transitions is very important, since they make your application unique and more intuitive to use. Also, if you combine custom view controller transitions with UI Kit Dynamics, you can really achieve spectacular results from a user experience prospective.

Building blocks

First of all, we can split the custom view transitions in two big families: non-interactive transitions and interactive transitions. The difference between these two groups is that the interactive transitions are controlled by the user through a continuous gesture. For example, a user can pan a view controller’s view to the left to animate the transition animation. While she is performing the pan gesture, an animation is performed. If she stops the pan gesture, the animation stops too. And finally, if she starts to the gesture in the opposite direction (panning to the right), the animation reverses.

Besides this classification, I personally use a different one based on the classes involved in the implementation of the transition. I divide view controller transitions in two main groups:

  1. If the transition is performed between 2 view controllers embedded in a navigation controller or a tab bar controller, then I call it an embedded custom transition.
  2. If the transition is performed from a view controller (parent) that presents a new view controller on the screen, then I call it a custom presentation transition.

Each of these groups can be interactive or non-interactive. Let’s analyze each of them separately.

Embedded Custom Transitions

In this type of transitions, the source view controller (or the from-view controller) and the destination view controller (or the to-view controller) must be part of a navigation controller or a tab bar controller.

If you are using a navigation controller, when you push a new view controller onto the navigation controller stack, the navigation controller looks for an animation controller, an object that conforms to the UIViewControllerAnimatedTransitioning protocol. In the same way, if you are using a tab bar controller, when you tap on a tab of the tab bar, the tab bar controller looks for an animation controller. If the navigation controller or the tab bar controller do not find the animation controller object, then they will use a default animation controller that will perform the default transitions. In case of a navigation controller, you will see the classic right-to-left transition. And in case of tab bar controller, you will see the classic appearing of the destination view controller.

TheUIViewControllerAnimatedTransitioning protocol provides you a reference to another object that conforms to a UIViewControllerContextTransitioning protocol. This object provides you with the information related with the view controllers involved in the custom transition. For example, it provides you with a reference to the from-view controller and a reference to the to-view controller. These are generic references that will make your transition completely independent of a particular view controller. In this way, the view controllers and your animation controller are fully decoupled, allowing you to reuse the same animation controller in other places of your app or in a different app, just copying and pasting the animation as I will show you later.

Navigation Controller Transition

Let’s build an example with a navigation controller. Create a new app and choose a Single-View Application. Choose Swift as language. Name the project Custom Navigation. Open the Storyboard and select the View Controller.

Select View Controller

Then go to the Xcode menu Editor > Embed In > Navigation Controller.

Embed view controller

In the navigation bar of the original view controller, let’s add on the right side a bar button item and change its title to be Next. This button will trigger the transition.

Let’s add a new view controller to the Storyboard and a new subclass of the UIViewController. Name this subclass SecondViewController. Change the type of the newly added storyboard’s view controller to SecondViewController. And now, control-drag from the bar button item to the second view controller. Choose Show as segue action. To make the transition more evident, let’s change the background color of the view controller’s views to two different colors.

Connect view controller

Now, let’s add some source code. First of all, we need to create the animation controller. This object is an instance of class that conforms to the UIViewControllerAnimatedTransitioning. So, let’s add a subclass NSObject to our project and let’s name it Animator. Make this class conforms to the transitioning protocol.

The UIViewControllerAnimatedTransitioning protocol provides 3 methods:

  1. func transitionDuration(_ transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval
  2. func animateTransition(_ transitionContext: UIViewControllerContextTransitioning)
  3. optional func animationEnded(_ transitionCompleted: Bool)

We must implement at least the first 2 methods (being required by the protocol). The first method provides you with a reference to the transitioning context. As mentioned, the transitioning context is an object that conforms to the UIViewControllerContextTransitioning protocol. You can use it to query information about the objects involved in the transition.

The transitionDuration(_:) method returns the duration of the animation. Let’s add the following implementation to our Animator class:

With this method, we are telling the animation controller that the transition will last 1 second.

The second method animateTransition(_:) performs the transition between the from-view controller and the to-view controller.

Before we implement this method, we need to write some code that instantiates the animation controller. We can use the navigation controller delegate. We could make the AppDelegate the delegate object of the navigation controller. Instead, let’s use the segue we already added in the storyboard. Add a new subclass of UIStoryboardSegue to the project. Let’s name it CustomSegue. Now, select the storyboard between the 2 view controller and change the class of the segue to CustomSegue in the Attribute Inspector. Let’s modify the class in this way:

In line 1, I make the CustomSegue class conform to the UINavigationControllerDelegate protocol. Then, I override the perform() method and before call it on super (that will actually trigger the segue), I set the custom segue as the delegate of the navigation controller. This allows me to use the method:

This method is triggered by the navigation controller whenever you push or pop a view controller to or from its stack. In this method, I instantiate the animation controller Animator.

As you can see, this delegate method gets as argument a reference to the navigation controller, the type of navigation operation (this can be: None, Push, or Pop), a reference to the from-view controller and a reference to the to-view controller. In this example, I need only the operation type, since I want to create 2 animations: one for the push transition and one for the pop transition.

In the Animator class, I add a new property that will hold the type of navigation operation and a designated initializer:

I also add two constant properties that I will use later in the animation:

Now, I can go back to the animateTransition(_:) method.

I want to build the following animation: when a view controller is pushed on to the navigation controller stack, the from-view controller moves back and the to-view controller comes from the right side of the screen. When a pop operation is performed, I want to move the from-view controller (that was the to-view controller in the push operation) to the right (going offscreen) and make the to-view controller (that was the from-view controller in the push operation) coming to the front.

Let’s start with the push operation. I am going to split our animation in two steps. First, I build the animation of the from-view controller moving back. I want to do it using a spring animation through the UIView animation API. In this case, I cannot apply any 3D transforms (view animations can perform only 2D animations). To make the illusion that the view controller moves back, I simply scale down the view controller view a 10% of its width and height.

In the animateTransition(_:) method, I get a reference to the from-view and to-view through the transitionContext:

Additionally, I get a reference to the containerView. This view is created by the transitioning context to contain the animation. I will use it as the superview of the views of each view controller.

Since I’m splitting the animation in 2 steps, I use half of the total animation duration to push the view controller back and half to move the next view controller in:

Then, I switch on the operation property:

The following code goes inside the push animation:

In line 1, I move the toView to the right side of the screen and prepare it for the second part of the animation. In line 2, I add it to the containerView. In line 3, I start the view animation using the spring damping and spring velocity defined in the properties. In line 4, I apply a scale transform to the fromView (notice that I did not need to add the fromView to the containerView since it is already there when the transition starts). In the completion block of the animation (line 5), I start the second part of the transition. Using the same spring damping and velocity (lines 6 and 7), I move the toView from the right side of the screen to the left (line 8) to cover completely the screen. In the completion block of this second animation (line 9), I finally tell the animation controller that the transition has completed (line 10).

The pop operation performs the reverse animation:

This animation is very similar to the previous one, so I don’t any additional comment. If you implemented everything correctly you should see the following transition:

The great advantage of this way of building custom transitions is that you can reuse the same animation controller in any view controller transition. As you can see, the animation controller does not know anything specific about the source and destination view controllers. It needs only a reference to them or to their views.

I leave you as exercise the implementation of the same transition with a tab bar controller. In this case, you need to make the CustomSegue conform to the UITabBarControllerDelegate protocol and implement the method:

Instead, let’s see what happens when you present a view controller on the screen from a parent view controller. In this case, you use what I call custom presentation transition.

Custom presentation transitions

In this case, the objects involved in the transition are again the animation controller. In addition, you need to work with the transitioning delegate object (an object that conforms to the UIViewControllerTransitioningDelegate). This object takes the place of the UINavigationControllerDelegate and the UITabBarControllerDelegate in the case of the embedded custom transitions. The transitioning delegate object is responsible of the presentation and the dismissal of the child view controller.

Presentation Controller Example

Let’ create a new SingleView Application project. Choose again Swift. Name the project Custom Presentation.

Go to the Main.storyboard file and add a button to the view controller’s view. Change its title to Present. Add also a new view controller to the storyboard. Control-drag from first view controller to newly added view controller and choose “Present modally” as action segue. Add a button to this view controller and change its title to Dismiss.

Let’s add a new UIViewController subclass to our project. Name it SecondViewController and associate it to the newly added view controller in the storyboard.

Now, let’s add a subclass of UIStoryboardSegue to the project. Name it CustomSegue. This time, I make the custom segue conform to the UIViewControllerTransitioningDelegate:

So, the custom segue will act as the transitioning delegate. In this class, I override again the perform() method and set self as the transitioning delegate of the destination view controller:

The UIViewControllerTransitionDelegate provides these methods:

I use the first method to instantiate the animation controller responsible for the presentation animation. Then, I use the second method to instantiate a different animation controller that is instead responsible for the dismissing animation.

In this example, I am going to use the same animations I implemented in the navigation controller example. I add to the project 2 new classes: PresentationAnimator and DismissalAnimator. You could make the custom segue conform to the UIViewControllerAnimatedTransitioning protocol and add the following source here. For didactic reasons, I am going to create two distinct classes, instead.
Both classes need to conform to the UIViewControllerAnimatedTransitioning protocol. And both of them must implement the transitionDuration(_:) and the animateTransition(_:) methods. Here the implementation of the PresentationAnimator class:

As you can see, this is similar source code I used for the custom transition with the navigation controller. The following is instead the implementation of the DismissalAnimator class:

To make the DismissalAnimator work, we need to unwind the segue. So, go to the ViewController.swift file and add the following action to it:

You can leave this action empty. Then, go to the storyboard and right-click the Exit object in the SecondViewController and connect it to the Dismiss button as shown here:

Unwind segue

Conclusions

I demonstrated how to combine the view controller custom transition APIs and the storyboard segues. This is a new feature introduced by Apple in iOS 9. Next time, I will show you how to create interactive transitions.

Geppy

Geppy Parziale (@geppyp) is cofounder of InvasiveCode (@invasivecode). He has developed iOS applications and taught iOS development since 2008. He worked at Apple as iOS and OS X Engineer in the Core Recognition team. He has developed several iOS and OS X apps and frameworks for Apple, and many of his development projects are top-grossing iOS apps that are featured in the App Store.

iOS Consulting | INVASIVECODE

iOS Training | INVASIVECODE