Nowadays, good design is so much more than how an app looks. It also has to “feel” right.
If you take a look at the animations and transitions in iOS, you will see that the interaction with an app is almost as important to the whole experience.
It is much more than just the visuals. Take a look at this post to see how custom transitions work in Swift using Autolayout
How to Use Transitions To Give Your App the Wow Factor
So how do you bring your app into the new age. iOS does have an answer for us.
One of the things I love most about the features launched in iOS 7 is the new Transitioning APIs. I’m sure you have seen those cool animated transitions in apps like Evernote and the National Geographic app. You get to see cool rotations, zooms and animations on the navigation bar and you wondered, how the *!?* did they do that?
Take a look at the transitions in this video.
Prior to iOS 7, it was a pain to implement custom transitions so this is a welcome addition. In some of our new templates, we implement a couple of custom transitions that give your app that unique edge.
You can find this in our new iOS templates Highlights and Trackbeam.
With custom transitions, you can display modal views or navigation hierarchy views that are pushed on the stack. I decided to extract the transition code into a simple smaller project and show you how we did it.
How Did We Do This?
Here’s the walkthrough.
First off, your initial View Controller (the one who initiates the transition) need to implement the UIViewControllerTransitioningDelegate protocol.
Most importantly, these two methods will be implemented
animationControllerForPresentedController:presentingController:sourceController:
and animationControllerForDismissedController:
The first method asks your View Controller for the suitable object to control the animation during presentation. The second method asks for another object that controls the animation during dismissal.
- (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { self.animationController.isPresenting = YES; return self.animationController; } - (id )animationControllerForDismissedController:(UIViewController *)dismissed { self.animationController.isPresenting = NO; return self.animationController; } |
These can be same object as long as you specify behaviours for both presentation and dismissal.
The Real Mccoy: The Animation Controller
Now we need to implement this controller class, the culprit for controlling the animations. It conforms to the UIViewControllerAnimatedTransitioning protocol. There is also a similar protocol for interactive transitions but let’s make it simple for now.
In our case, we have a class called the DropAnimation controller and it implements a method called animationTransition.
This is the method below. It checks whether we are presenting or dismissing a controller, then executes the correct method.
-(void)animateTransition:(id)transitionContext{ if(self.isPresenting){ [self executePresentationAnimation:transitionContext]; } else{ [self executeDismissalAnimation:transitionContext]; } } |
Now this is where the magic happens. The executePresentationAnimation method adds the new controller to the stage and then uses the new Spring animation methods on UIView to push in the view from the top as a modal view.
-(void)executePresentationAnimation:(id)transitionContext{ UIView* inView = [transitionContext containerView]; UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; [inView addSubview:toViewController.view]; CGPoint centerOffScreen = inView.center; centerOffScreen.y = (-1)*inView.frame.size.height; toViewController.view.center = centerOffScreen; [UIView animateWithDuration:self.presentationDuration delay:0.0f usingSpringWithDamping:0.4f initialSpringVelocity:6.0f options:UIViewAnimationOptionCurveEaseIn animations:^{ toViewController.view.center = inView.center; } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }]; } |
And when dismissing, the reverse happens. We swing the view back up the stage and out of view.
-(void)executeDismissalAnimation:(id)transitionContext{ UIView* inView = [transitionContext containerView]; UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; [inView insertSubview:toViewController.view belowSubview:fromViewController.view]; CGPoint centerOffScreen = inView.center; centerOffScreen.y = (-1)*inView.frame.size.height; [UIView animateKeyframesWithDuration:self.dismissalDuration delay:0.0f options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{ [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.5 animations:^{ CGPoint center = fromViewController.view.center; center.y += 50; fromViewController.view.center = center; }]; [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^{ fromViewController.view.center = centerOffScreen; }]; } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }]; } |
Get the source code
I hope you are as excited to get new transitions into your app. Check out the Eventer template to get the full featured design with custom animations.
You can download the sample animation I just described above here