简体   繁体   English

UINavigationController:如何取消后退按钮事件?

[英]UINavigationController: How to cancel the back button event?

In my UIViewController I have a UINavigationController with a default back button. 在我的UIViewController我有一个带有默认后退按钮的UINavigationController 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: 它只能使用viewWillDisappear并设置一个标志:

- (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)alertView:(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 ? 我是否必须编写自己的后退按钮并将其设置为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. 我已经实现了UIViewController-BackButtonHandler扩展。 It does not need to subclass anything, just put it into your project and override navigationShouldPopOnBackButton method in UIViewController class: 它不需要子类化任何东西,只需将它放入您的项目并覆盖UIViewController类中的navigationShouldPopOnBackButton方法:

-(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! viewWillDisappear是视图将要消失的事件的委托方法 - 开发人员无法做到这一点! If you could, it would be a viewShouldDisappear delegate method. 如果可以的话,它将是一个viewShouldDisappear委托方法。

So I guess the only way is as you suggest, to use a custom leftBarButtonItem . 所以我想你唯一的方法是使用自定义的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. 正如许多人所指出的, UINavigationBarDelegate以下方法是实现此功能的关键。

- (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 . 许多人已经将UINavigationController子类化并实现了上述方法,使其易于使用而无需直接访问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. 虽然看起来有必要, popViewControllerAnimated:在此方法中报告了崩溃,调用popViewControllerAnimated: .
  • 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 . 我们需要通过设置代理来拦截手势,如https://stackoverflow.com/a/23173035/2400328中所述

If the UINavigationController is subclassed, that would be: 如果UINavigationController是子类,那将是:

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: 不调用popViewControllerAnimated:

Although undocumented, calling popViewControllerAnimated: can be avoided as in https://stackoverflow.com/a/26084150/2400328 . 虽然没有记录, popViewControllerAnimated:可以像https://stackoverflow.com/a/26084150/2400328一样避免调用popViewControllerAnimated: .

It involves calling navigationBar:shouldPopItem: of UINavigationController (from the subclass). 它涉及调用UINavigationController (来自子类)的navigationBar:shouldPopItem: .

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 虽然这可能是一个小细节(特别是,如果你设计了自己的后退按钮),有一个简单的解决方案(由我编写:) https://stackoverflow.com/a/29440633/2400328

You only need to set a property YES and NO. 您只需要设置属性YES和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. 您可以使用带有图形的自定义按钮,它看起来与“后退”按钮完全相同,并使用此图形创建自定义leftBarButtonItem视图作为UIButton Add target self to your button with custom back: selector and pop your alert there. 使用自定义back:选择器将目标self添加到按钮,然后在此处弹出警报。 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. 这里的诀窍是按钮,它看起来与导航栏的后退按钮完全相同。

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: 如果您正在寻找在iOS 10上的Swift中执行此操作的方法,您可以创建自定义UINavigationController ,然后创建UINavigationBarDelegate扩展:

class MyNavigationController : UINavigationController {

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

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 这绝对可以帮助你执行任何操作

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 :( 不幸的是我们不应该将UINavigationBar委托给我们自己的对象:(

The Apple Documentation states : Apple文档声明:

... In addition, a navigation controller object automatically assigns itself as the delegate of its UINavigationBar object and prevents other objects from changing that relationship. ...此外,导航控制器对象会自动将其自身指定为其UINavigationBar对象的委托,并防止其他对象更改该关系。 ... ...

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. 如果允许用户返回

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM