iOS 7 Back Button Pop Gesture

29,487

Solution 1

Just add the following line of code:

[self.navigationController.interactivePopGestureRecognizer addTarget:self action:@selector(handleGesture:)];

You can add your own UIGestureRecognizer and pop the UIViewController yourself. See the docs for further info.

Solution 2

There is no need to add your own gesture recognizer. The UINavigationController already does that for you. You need to set the delegate for the interactivePopGestureRecognizer before enabling it.

Do the following two things:

self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
[self.navigationController.interactivePopGestureRecognizer setEnabled:YES];

Solution 3

I use

[[UINavigationBar appearance] setBackIndicatorImage:[UIImage imageNamed:@"nav_back.png"]];
[[UINavigationBar appearance] setBackIndicatorTransitionMaskImage:[UIImage imageNamed:@"nav_back.png"]];

[UIBarButtonItem.appearance setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -64) forBarMetrics:UIBarMetricsDefault];

Solution 4

To avoid crashes you have to be careful how you add and remove your custom back selector. The reason is that the navigation controller stays around while you pushing popping controller. As already stated after adding your custom back button+selector, you should do the following in viewDidApear.

    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
    {
       self.navigationController.interactivePopGestureRecognizer.enabled = YES;
       self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
       [self.navigationController.interactivePopGestureRecognizer addTarget:self action:@selector(navigateBack)];
    }

Then in viewWillDisapear do

        if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
        {
           [self.navigationController.interactivePopGestureRecognizer removeTarget:self action:@selector(performCompletion)];
        }

The timing of these calls is a key. You can run into crashes otherwise, see more details on the reason in here

Solution 5

There is a new gesture recognizer UIScreenEdgePanGestureRecognizer. You can add it to your view and handle respectively (call navigateBack), replicating view controllers navigation behaviour.

Share:
29,487
dlinsin
Author by

dlinsin

Freund und Papa • Kaffee-Liebhaber &amp; Katzen-Zähmer • Hockey Fan • Holzwerker

Updated on August 09, 2022

Comments

  • dlinsin
    dlinsin over 1 year

    In iOS 7 there's the new swipe to pop gesture: You swipe from left to right on the left side of your screen and the UINavigationController pops back to the previous UIViewController.

    When I create a custom back button like this, the swipe to pop gestures doesn't work anymore:

    UIBarButtonItem *customBackButton = [[UIBarButtonItem alloc] initWithTitle:@" " style:UIBarButtonItemStyleBordered target:self action:@selector(navigateBack)];
    [customBackButton setBackButtonBackgroundImage:barBackBtnImg forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
    [customBackButton setBackButtonBackgroundImage:barBackBtnImgHighlighted forBarMetrics:UIBarMetricsDefault];
    self.navigationItem.backBarButtonItem = customBackButton;
    

    How can I use a custom back button and have the native swipe to pop gesture?

    Update:

    That's what's happening in navigateBack:

    - (void)navigateBack {
        [self.navigationController popViewControllerAnimated:YES];
    }
    
  • dlinsin
    dlinsin over 10 years
    Yep that's what's in navigateBack. I'll add it to the question, thanks!
  • hsafarya
    hsafarya over 10 years
    Tried that way and action is not called, but I used my custom back button. When using standard back button this action called.
  • Dean Davids
    Dean Davids over 10 years
    This should be the correct answer. I just went all through creating a custom transition and manipulating the pop process manually with UIScreenEdgePanGestureRecognizer of my own. Came across your answer here and said, wth, give it a try. Works perfectly with two lines of code.
  • jsadler
    jsadler over 10 years
    I've found that this can lead to some pretty funky behaviour if you start a back gesture during a UINavigationController transition. For instance, if I tap a button that pushes a new controller onto the UINavigationController's stack and immediately swipe backwards, I get stuck in a middle state where the nav bar shows as if I was at the first screen (push, then pop) but the contents of the nav controller show the second scree, as if the pop never happened. I'm now using the solution 码农白腩肚 proposed, but that's still a bit of a hack.
  • udit gupta
    udit gupta over 10 years
    Yeah. I have witnessed this behaviour myself. If you are using a UINavigationController with a UINavigationBar there is no need to use this bit of code. The navigation bar handles it by itself and you are not stuck in that middle state.
  • surfrider
    surfrider over 9 years
    This leads to crash: for example you have VC1 (as root VC) and VC2. You push from VC1 to VC2 and then pop back. Now, make a swipe gesture on VC1 and IMMEDIATELY push to VC2 again. For me result is crash. Or you can swipe several times on VC1 after popping back from VC2, my test app crashes again. I must notice that instead of @selector(performCompletion) i used NULL Disabling interactivePopGestureRecognizer in viewDidAppear in VC1 leads to another bugs.
  • Markus
    Markus over 8 years
    This also works if you have navigationBar hidden. Thank you!
  • Dmitriy Kalachniuk
    Dmitriy Kalachniuk over 8 years
    Thank you! Saved a lot of time