How to change the Push and Pop animations in a navigation based app

Viewed 225527

I have a navigation based application and I want to change the animation of the push and pop animations. How would I do that?

Edit 2018

There have been many answers to this question and it's been quite awhile now, I have re-chosen the answer to what I believe to be the most relevant now. If there is anyone that thinks otherwise please let me know in comments

25 Answers

@Luca Davanzo's answer in Swift 4.2

public extension UINavigationController {

    /**
     Pop current view controller to previous view controller.

     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func pop(transitionType type: CATransitionType = .fade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.popViewController(animated: false)
    }

    /**
     Push a new view controller on the view controllers's stack.

     - parameter vc:       view controller to push.
     - parameter type:     transition animation type.
     - parameter duration: transition animation duration.
     */
    func push(viewController vc: UIViewController, transitionType type: CATransitionType = .fade, duration: CFTimeInterval = 0.3) {
        self.addTransition(transitionType: type, duration: duration)
        self.pushViewController(vc, animated: false)
    }

    private func addTransition(transitionType type: CATransitionType = .fade, duration: CFTimeInterval = 0.3) {
        let transition = CATransition()
        transition.duration = duration
        transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
        transition.type = type
        self.view.layer.add(transition, forKey: nil)
    }

}

Using iJordan's answer as inspiration, why not simply create a Category on UINavigationController to use throughout your app instead of copying/pasting this animation code all over the place?

UINavigationController+Animation.h

@interface UINavigationController (Animation)

- (void) pushViewControllerWithFlip:(UIViewController*) controller;

- (void) popViewControllerWithFlip;

@end

UINavigationController+Animation.m

@implementation UINavigationController (Animation)

- (void) pushViewControllerWithFlip:(UIViewController *) controller
{
    [UIView animateWithDuration:0.50
                     animations:^{
                         [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                         [self pushViewController:controller animated:NO];
                         [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
                     }];
}

- (void) popViewControllerWithFlip
{
    [UIView animateWithDuration:0.5
                     animations:^{
                         [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                         [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
                     }];

    [self popViewControllerAnimated:NO];
}

@end

Then simply import the UINavigationController+Animation.h file and call it normally:

[self.navigationController pushViewControllerWithFlip:[[NewViewController alloc] init]];

[self.navigationController popViewControllerWithFlip];

I am not aware of any way you can change the transition animation publicly.

If the "back" button is not necessary you should use modal view controllers to have the "push from bottom" / "flip" / "fade" / (≥3.2)"page curl" transitions.


On the private side, the method -pushViewController:animated: calls the undocumented method -pushViewController:transition:forceImmediate:, so e.g. if you want a flip-from-left-to-right transition, you can use

[navCtrler pushViewController:ctrler transition:10 forceImmediate:NO];

You can't change the "pop" transition this way, however.

I know this thread is old, but I thought I'd put in my two cents. You don't need to make a custom animation, there's a simple (maybe hacky) way of doing it. Instead of using push, create a new navigation controller, make the new view controller the root view controller of that nav controller, and then present the nav controller from the original nav controller. Present is easily customizable with many styles, and no need to make a custom animation.

For example:

UIViewcontroller viewControllerYouWantToPush = UIViewController()
UINavigationController newNavController = UINavigationController(root: viewControllerYouWantToView)
newNavController.navBarHidden = YES;
self.navigationController.present(newNavController)

And you can change the presentation style however you want.

Related