Since iOS 7 is mentioned in this question, I am very surprised that the answer does not mention the Animated Transitions API introduced in iOS 7.
If you want to go straight to GitHub, the objc.io guys have a great post with a related project here
Take a look at the documentation and you will see the following:
@availability(iOS, introduced=7.0) optional func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?
Or in Objective-C
- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
This means that from iOS 7 you can control how the navigation controller implements its animations for taps and exits.
All you need to do is set the delegate of the navigation controller and, if necessary, provide the correct animator object. So let's get started:
1. Set UINavigationControllerDelegate
I usually like to have an App-Wide navigation coordinator that manages all my transitions, etc. Ideally, you want an object to be alive throughout the entire navigation period of the NavigationController. So we can have a coordinator that looks like this:
class NavigationCoordinationController: NSObject { private(set) var navigationController:UINavigationController required init(navigationController: UINavigationController) { self.navigationController = navigationController super.init() navigationController.delegate = self } }
I usually create this in the App Delegate, so it can be referenced anywhere. You can also set a delegate based on each controller by creating a custom subclass of UINavigationController or wherever you are.
2. Create a custom animator
Now we need an object that conforms to the UIViewControllerAnimatedTransitioning protocol. This object will be called upon to apply animation whenever an animated transition is needed. This example is a simple animation that fades and extends the fromView value on transition, so it matters for Push.
class CustomPushExpansionTransitioner: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval { return 1 } func animateTransition(transitionContext: UIViewControllerContextTransitioning) { let fromView: UIView = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)! let toView: UIView = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)! let container = transitionContext.containerView() container.addSubview(toView) container.bringSubviewToFront(fromView) toView.frame = container.convertRect(fromView.bounds, fromView: fromView) UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in fromView.alpha = 0 fromView.transform = CGAffineTransformConcat(fromView.transform, CGAffineTransformMakeScale(1.3, 1.3)) }) { (complete) -> Void in transitionContext.completeTransition(true) } } }
3. Vend Animator Where Necessary
Now we need to implement the UINavigationController delegate and, if necessary, provide our custom animator.
extension NavigationCoordinationController: UINavigationControllerDelegate { func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { switch operation { case .Push: return LaunchToHomeTransitioner() case .Pop: break case .None: break } return nil } }
And now, you now have full control over the transitions of the UINavigationController