Prevent the animation when clicking "Back" button in a navigation bar?

20,077

Solution 1

More elegant with a category. This assumes you navigation controller object is set in your app delegate. Just put this before your @implementaion in the root view controller.

#import "AppDelegate.h"

@implementation UINavigationBar (custom)
- (UINavigationItem *)popNavigationItemAnimated:(BOOL)animated;
{

    AppDelegate *delegate = [[UIApplication sharedApplication] delegate];

    [delegate.navController popViewControllerAnimated:NO];

    return TRUE;
}


@end

Solution 2

This prevents default animation.

- (void)viewWillDisappear:(BOOL)animated {
    [UIView setAnimationsEnabled: NO];
}

- (void)viewDidDisappear:(BOOL)animated {
    [UIView setAnimationsEnabled: YES];
}

In case if you need a custom animation

- (void)viewWillDisappear:(BOOL)animated {
    [UIView setAnimationsEnabled: NO];

    CATransition *transition = [CATransition animation];
    transition.duration = 0.3;
    transition.type = kCATransitionFade;
    [self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
}

- (void)viewDidDisappear:(BOOL)animated {
    [UIView setAnimationsEnabled: YES];
}

Solution 3

I came to SO looking for a more elegant solution, but here's how I've been (successfully) doing it so far.

The basic idea:

  1. DO NOT use UINavigationController; instead use it's constituent parts (e.g. UINavigationBar) and do the work yourself
  2. Trigger the navbar to animate in parallel with your own custom animations (or not, if you want no anim at all)

The downsides:

  1. UINavigationController handles some other things, like memory loading/unloading, automatically. Also, it's "hard coded" into all UIViewControllers - they ALWAYS have a reference to the UINavigationController that contains them. It's a shame to throw all this away just because Apple doesn't provide a hook for setting custom anims.

Code - in whichever class takes over for the animation:

UINavigationItem *backItem = [[UINavigationItem alloc] initWithTitle:@"Back"];
[navigationController.navigationBar pushNavigationItem:backItem animated:TRUE];
// next line only needed if you want a custom back anim too
navigationController.navigationBar.delegate = self;

...if you also want to cut-in with custom back animation, you need that last line above, so that you can then listen to the navbar, and react in parallel, like this:

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
    // trigger your custom back animation here

    return TRUE;
}

Solution 4

Not that you should, however you can override the standard behaviour by creating a custom leftBarButtonItem in your viewController.

UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:@"Back" style: UIBarButtonItemStylePlain target:self action:@selector(backButtonPressed)];
[[self navigationItem] setLeftBarButtonItem:item];
[item release];

- (void)backButtonPressed
{
    [[self navigationContoller] popViewControllerAnimated:NO];
}

The documentation says that you should only pass NO before the nav controller's view is displayed.

Remember that applications that do not conform to the iPhone Interface Guidelines will not be accepted into the app store.

Share:
20,077
Dirty Henry
Author by

Dirty Henry

Software Engineer at Memo Bank. For more information about me, please refer to my website.

Updated on June 18, 2020

Comments

  • Dirty Henry
    Dirty Henry almost 4 years

    My application has a navigation controller and I don't want any animation in it :

    • to prevent an animation when pushing a view, it's easy, via the pushViewController:animated: method

    • but when I click the "back" button on this subview, there's an animation ! KO ! What can I do to prevent this animation ?

  • Adam
    Adam almost 14 years
    That code is buggy, and even then only partially works. You won't get the "arrow" shape button. Typo in your code - missing "]" on line 1. Also, your code in line 2 is incorrect - I believe it should read: "[self.navigationItem setLeftBarButtonItem:item];" w.r.t. "is this acceptable by Apple": 1. That's not true - many many applications that violate the HIG are accepted; many of Apple's own applications flagrantly violate it. 2. Any time you want to do a custom push/pop animation pair, you NEED to disable the default one (since Apple does not provide a public API for overriding it).
  • Dirty Henry
    Dirty Henry almost 14 years
    Thanks for your answer ! But you're right : i'm too lazy to throw all the UINavigationController features away and I prefer allowing the animation to occur ;)
  • Dirty Henry
    Dirty Henry almost 14 years
    Thanks for your answer. Nevertheless, I agree with Adam : the "arrow" shape is a MUST have in an iPhone application.
  • lothorp
    lothorp about 13 years
    You can always re-create the arrow image. I think that's a fairly common practice, since apple doesn't give you a way to make one programmatically.
  • Dirty Henry
    Dirty Henry almost 13 years
    Thanks for your answer, i've just tried it and it actually works but it is surprising because you return TRUE for something expecting a UINavigationItem.
  • Dirty Henry
    Dirty Henry almost 13 years
    Also, this solution works if you have 1 and only 1 navigation controller in your app. It won't work with multiple navigation controllers.
  • János
    János almost 12 years
    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot manually set the delegate on a UINavigationBar managed by a controller.'
  • Abdul Yasin
    Abdul Yasin about 10 years
    it just getting bounce over my head. Plz explaian . i am new bie. Thals
  • Abdul Yasin
    Abdul Yasin about 10 years
    What is going on here. i couldn't understand anything. plz somebody help me
  • Martin
    Martin about 10 years
    A category adds or replaces methods in a class. This category method replaces the - (UINavigationItem *)popNavigationItemAnimated:(BOOL)animated; method and changes the behaviour.
  • nalexn
    nalexn about 10 years
    -1 for using TRUE instead of YES. By the way, the return type is UINavigationsItem *, not a boolean
  • Martin
    Martin about 10 years
    Bit harsh -> stackoverflow.com/questions/615702/…. And why instantiate something to return that you know will be ignored?
  • George Asda
    George Asda about 8 years
    @Martin is there a way to achieve this in swift?