How To Make A UIViewController Transition Animation Like in the Ping App
iOS supports custom transitions between view controllers. In this tutorial you’ll implement a UIViewController transition animation like the Ping app. By Luke Parham.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How To Make A UIViewController Transition Animation Like in the Ping App
25 mins
- Strategizing
- Getting Started
- Navigation Controller Delegates
- The UIViewControllerAnimatedTransitioning Protocol
- The CircleTransitionable Protocol
- Animating the Old Text Away
- Fixing the Background
- The Circular Mask Animation
- CAShapeLayer
- CALayer Masking
- Animations with Core Animation
- The Finishing Touches
- Where to Go From Here?
A while back, the makers of the anonymous social networking app Secret released an app called Ping, which allowed users to receive notifications about topics they were interested in.
One thing that stood out about Ping, aside from it’s unpredictable recommendations, was the circular transition between the main screen and the menu, as seen in the animation to the right.
Naturally, when you see something cool you want to see if you can figure out how they did it. Even if you’re some kind of nerd who doesn’t think that about every animation you see, you’ll get to learn a lot about view controller transition animations while exploring this animation.
In this tutorial, you’ll learn how to implement this cool animation in Swift using a UIViewController transition animation. In the process, you’ll learn about using shape layers, masking, the UIViewControllerAnimatedTransitioning
protocol, the UIPercentDrivenInteractiveTransition
class, and more.
Existing knowledge of view controller transition animations is useful, but not required for this tutorial. If you want an intro to the topic first, be sure to check out Custom UIViewController Transitions: Getting Started.
Strategizing
In Ping, the UIViewController transition animation happened when you went from one view controller to another.
In iOS, you can write custom transitions between view controllers by putting both view controllers inside a UINavigationController
, and implementing iOS’s UIViewControllerAnimatedTransitioning
protocol to animate the transition.
One thing to keep in mind before getting started is that you can implement these animations using any method you want, be it pop, UIView, UIKit Dynamics or the lower-level Core Animation APIs.
In this tutorial, you’ll be focusing on the standard UIView and Core Animation APIs.
Now that you know where the coding action happens, it’s time to think about how to actually implement the circle transition.
Just from looking, a good guess about the animation’s implementation goes something like:
- There’s a circle that originates from the button on the top right; it acts as a viewport into the view that’s appearing.
- The text of the view controller you’re leaving grows and animates offscreen to the left.
- The text of the view controller you’re moving to grows and fades in from the right; within the visible space of the expanding circle.
Now that you know vaguely what you’re going for, it’s time to get started.
Getting Started
To begin, download the starter app. If you build and run you’ll see an app that’s been created to mirror the simple elegance of text on a colored background. Go ahead and do so and tap that circular button a few times.
As you can see, you’ve got a boring old default push and pop animation on your hands. My mom always told me I could do anything if I put my mind to it so now I’m telling you, you can make this transition better!
Navigation Controller Delegates
UINavigationController
instances have a delegate property that can be any object that implements the UINavigationControllerDelegate
protocol.
The other four methods in this protocol have to do with reacting to view controllers being shown and specifying which orientations are supported, but there are two methods that allow you to specify objects that are responsible for implementing custom transitions.
Before you get too carried away, you’ll want to make a new class that can take care of being this delegate for your app.
With the starter app open and the Pong group selected, press ⌘+N to start adding a new file. Choose Cocoa Touch Class from the options and click Next. Name the new class TransitionCoordinator and make sure it’s set to Subclass of: NSObject and Language: Swift. Hit Next and then Create.
This class needs to adhere to the UINavigationControllerDelegate
protocol. Change the class definition line to:
class TransitionCoordinator: NSObject, UINavigationControllerDelegate {
So far so good, next you’ll implement the only delegate method you care about at the moment. Add the following method to TransitionCoordinator
:
func navigationController(_ navigationController: UINavigationController,
animationControllerFor operation: UINavigationControllerOperation,
from fromVC: UIViewController,
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return nil
}
All this method needs to do is look at which view controller it’s moving from, along with the one it’s moving to and return an appropriate animation object for the pair.
At the moment, you’re just returning nil
which is what’s been happening all along by default. When a navigation controller asks for an animation controller for a certain transition and receives nil
, it ends up using the default push and pop transitions you saw earlier.
You’ll come back to this class to return a proper animation controller object in a little bit.
In AppDelegate.swift add the following just below the window property declaration:
let transitionCoordinator = TransitionCoordinator()
This initializes a TransitionCoordinator
and keeps a strong reference to it.
Now find the line where you’re hiding the navigation bar:
nav.isNavigationBarHidden = true
After this line, assign the TransitionCoordinator
to be the navigation controller’s delegate with the following:
nav.delegate = transitionCoordinator
Build and run to confirm it runs. You won’t see anything new happening yet since the delegate is returning a nil
animation.
Yeah, I know it’s boring, I told you!
The UIViewControllerAnimatedTransitioning Protocol
The “animation object” the TransitionCoordinator
will return is just something that conforms to UIViewControllerAnimatedTransitioning
.
Objects that conform to this protocol have a simple job. They only really need to implement two methods. The first is a method that returns how long the transition will take in seconds. The second is a method that takes in a context object with all the information it needs to actually perform the animation.
A really common pattern is to create the animation object and assign it the UINavigationControllerOperation
argument if your transition looks different between pushing and popping.
In this case, you don’t actually need to do it; the transition is the same whether you’re pushing or popping so if you write it generically, it will just work regardless of the direction you’re going.
Now that you know what you need, it’s time to write a new class. Press ⌘+N again, make another Cocoa Touch Class and this time, name it CircularTransition.
The first thing you need to do with your new class is have it conform to the UIViewControllerAnimatedTransitioning
protocol. To do so, just add it after the NSObject
inheritance declaration like so:
class CircularTransition: NSObject, UIViewControllerAnimatedTransitioning {
Per usual, you’ll immediately be told that your class doesn’t conform to this protocol. Well you just tell Xcode to be cool, cause that’s exactly what you’re about to do!
First, add the method that specifies how long our animation is going to take.
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?)
-> TimeInterval {
return 0.5
}
This is the first method UIKit will call on your transition object after it’s been provided by the navigation controller delegate. Here you’re just saying that this transition should take around half a second to complete.
Next, add an empty definition of the actual animation method that you’ll come back to later.
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
//make some magic happen
}
This is where you’ll receive a transition context object that will have all the information you’ll need to write your animation code.
Head back over to TransitionCoordinator.swift and replace the current nil return statement with something a little more useful:
return CircularTransition()
Here, you’re telling the navigation controller that you’re sick of that boring push and pop transition it keeps trying to use and you’ve got something better in mind. Internally, UIKit will take this UIViewControllerAnimatedTransitioning
object and use it to drive the animations for all transitions that occur for this navigation controller from now on.
It is pretty awesome that this is open to you, but remember, with great power, comes a lot of work. So head back to CircularTransition.swift and brace yourself for the real work!