In my previous blog post on view controller transitions I demonstrated how to create a page-fold animation controller. In this blog post, I’ll take the concepts a step further by showing how to create interactive tab bar controller transitions.
If you watched the WWDC video #218 “Custom Transitions Using View Controllers” you will have seen a demonstration that showed a tabbed interface where you can swipe left and right to navigate, with the view controllers folding like paper:
This blog post will show how to replicate this effect.
Here is a quick video of the effect that the transition produces:
A brief introduction to custom transitions
The following provides a very brief introduction to the concepts, for more detailed coverage I would thoroughly recommend reading Chapter 3 of iOS 7 By Tutorials - which I wrote! (I’ve heard the other 15 chapters are pretty good too ;-)
There are two key classes involved in a custom transition:
- Animation controller - this class is responsible for performing the custom transitions. When you indicate that a custom transitions should be used, you provide an animation controller. This class performs the required animation, then informs the framework when it has completed.
- Interaction controller - this class is responsible for managing interactive transitions - these are transitions that typically controlled by a gesture, allowing the user to swipe, pinch or perform some other action to navigate between view controllers. Importantly, interaction controllers allow transitions to be cancelled, i.e. a user can start the navigation, change their mind, and reverse it!
NOTE: Animation and interaction controllers are entirely independent, this means you can wire up any interaction controller with any animation controller - which is pretty awesome.
Setting up the animation
The first step is to create an animation controller which ‘folds’ the views as it transitions between them. This will use may of the same techniques I discussed in my previous blog post - snapshots, transforms and UIView
animations.
The first step is to use the snapshotting API to create a copies of the from- and to- views. These copies are arranged in vertical strips, which make up the folds. The following code is executed when the animation is initiated:
This makes use of a utility method which creates a ‘strip’ at the given offset location:
Notice that the above method sets the anchor point of the snapshot view to either its left or right edge. Transforms use the anchor point as their origin, therefore setting the anchor point to an edge makes it easier to rotate the view around that edge.
If you add a border to the snapshots you can see how they are arranged vertically as shown below:
In the above screenshot you can see the ‘sliced’ view that is being navigated from, but where is the view that is navigated to? In the above code that creates the snapshots, each of the to- views has the following applied:
All the to- views are located on the left hand edge of the screen and rotate by 90 degrees so that they are not visible to the viewer.
If we rotate the viewport just a little, and make the layers opaque, you can see the to- views all bunched up at the edge:
Animating the transition
The animation is surprisingly simply, within a single UIView animation, we iterate over the folds, setting the final state of each of the snapshots:
The above code iterates over the folds, retrieving the snapshot views from the arrays that were created earlier. The from- view snapshots are rotated by 90 degrees and have their position set to locate them at the right edge of the screen - much the same as the to- view snapshots were rotated by 90 degrees and located at the left edge at the start. The to- view snapshots simply have their transform removed and are moved to their final location.
Fortunately, as the animation interpolates the frame for each layer and simultaneously rotates it, the edges are always in contact with the neighbours:
One thing you have to do is make sure you ‘clean up’ after your animation. In the case of this animation, you have to remove all the snapshot views and restore the from- and to- view to their original locations:
One important thing to not here is that because the animation is achieved using a single UIView animation, this animation controller will work with the framework’s UIPercentDrivenInteractiveTransition
class. This is a big bonus, because it means that the framework can play, rewind and step through the animation in order to make it interactive.
Adding some depth
In order to add a bit of realism and depth, I used the same technique as I described in my previous blog post, using a simple utility method to add a gradient as a child of a given view:
With this in place, the snapshots now have a gradient as shown below:
The final step is to animate the alpha value of these gradient views along with the existing animations, so that the gradient is darker as the fold increases:
Done!
Going interactive
Interaction controllers are associated with views, adding gesture recognisers, which trigger interactive transitions. In order to make tab bar controller transitions interactive, a horizontal swipe feature seems appropriate.
When the gesture starts, the swipe direction is used to determined whether to increment or decrement the tab index:
Other than the above, integrating with a tab bar controller is just the same as the required navigation controller integration.
You can obtain the source code for this interactive transition form the VCTransitionsLibrary project on GitHub.
Regards, Colin E.