开发者

UINavigationController: How to cancel the back button event?

In my UIViewController I have a UINavigationController with a default back button. When the user clicks the back button, a warning message should appear: "Do you really want to go back?". I know, that it is not possible to trap the back button event. It's only possible the use viewWillDisappear and set a flag:

- (void)viewWillDisappear:(BOOL)animated {
    if (backBtnPressed) {
        UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Question" message:@"Do you really want to go back?" delegate:self cancelButtonTitle:@"No" otherButtonTitles: @"Yes", nil] autorelease];
        [alert show];   
    }
}

- (void)alertV开发者_开发知识库iew:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
    if (buttonIndex == 0) {
        // don't go back!
        // cancel the back button event
    }
    else if (buttonIndex == 1) {
        // go back
    }
}

But with this code I have no chance! I can't stop the back button event, isn't it?

Do I have to write my own back button and set it as leftBarButtonItem? Or is there anybody with a great idea? :-)

Thanks for your help!


My answer from another thread matches this question. So I repost it here:

I've implemented UIViewController-BackButtonHandler extension. It does not need to subclass anything, just put it into your project and override navigationShouldPopOnBackButton method in UIViewController class:

-(BOOL) navigationShouldPopOnBackButton {
    if(needsShowConfirmation) {
        // Show confirmation alert
        // ...
        return NO; // Ignore 'Back' button this time
    }
    return YES; // Process 'Back' button click and Pop view controller
}

Download sample app.


What you need to do is to use the delegate of the navigation bar, and not the navigation controller.

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPushItem:(UINavigationItem *)item; // called to push. return NO not to.
- (void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item;    // called at end of animation of push or immediately if not animated
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;  // same as push methods
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item;


viewWillDisappear is a delegate method for the event that the view is going to disappear - and there's nothing the developer can do about that! If you could, it would be a viewShouldDisappear delegate method.

So I guess the only way is as you suggest, to use a custom leftBarButtonItem.


I must say this is one of the common use cases that Apple doesn't seem to make easy, and I see a lot of effort trying to get this working. I thought maybe I should summarize my findings here.

As many have pointed out, the method below in UINavigationBarDelegate is key to implementing this feature.

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;

Many have subclassed UINavigationController and implemented the method above to make it easy to use without direct access to the UINavigationBar.

Unfortunately, there still remain some issues.

  • The swipe back gesture does not invoke this method.
  • Although it seems necessary, crashes are reported calling popViewControllerAnimated: in this method.
  • The Back button remains grayed out, when pop is cancelled.

Swipe back gesture

We need to intercept the gesture by setting the delegate as is done in https://stackoverflow.com/a/23173035/2400328 .

If the UINavigationController is subclassed, that would be:

self.interactivePopGestureRecognizer.delegate = self

and implementing:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

Take care in when you modify the delegate property, as it gets modified after the initializer is called.

Not calling popViewControllerAnimated:

Although undocumented, calling popViewControllerAnimated: can be avoided as in https://stackoverflow.com/a/26084150/2400328.

It involves calling navigationBar:shouldPopItem: of UINavigationController (from the subclass).

The Back button

Although this may be a minor detail (especially, if you have designed your own Back button), there is a simple solution (written by me :) https://stackoverflow.com/a/29440633/2400328

You only need to set a property YES and NO.

auto item = navigationBar.topItem;
item.hidesBackButton = YES;
item.hidesBackButton = NO;


You can use a custom button with a graphics, which looks exactly like "Back" button and create a custom leftBarButtonItem view as UIButton with this graphics. Add target self to your button with custom back: selector and pop your alert there. If the user presses "yes" to quit dismiss this view controller, if not - do nothing. The trick here is the button which looks exactly as navigation bar's back button.


Its better if u make your own back button and make it the left button of the Navigation controller. That can definitely help u to perform any action


If you're looking for a way to do this in Swift on iOS 10, you can create a custom UINavigationController and then a UINavigationBarDelegate extension:

class MyNavigationController : UINavigationController {

}
extension MyNavigationController : UINavigationBarDelegate {
    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        return false
    }
}


The Method

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;

is doing what you want. Unfortunately we are not supposed to delegate UINavigationBar to our own objects :(

The Apple Documentation states :

... In addition, a navigation controller object automatically assigns itself as the delegate of its UINavigationBar object and prevents other objects from changing that relationship. ...

One/The? way to do what you want is to put in your own back-button. In that Method you do your tests and call

[self.navigationController popViewControllerAnimated:true];

if the user is allowed to go back.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜