【问题标题】:UINavigationController: How to cancel the back button event?UINavigationController:如何取消后退按钮事件?
【发布时间】:2011-02-25 08:34:37
【问题描述】:

在我的UIViewController 中,我有一个带有默认后退按钮的UINavigationController。当用户单击返回按钮时,应该会出现一条警告消息:“您真的要返回吗?”。我知道,不可能捕获后退按钮事件。只能使用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
    }
}

但是有了这段代码,我就没有机会了!我无法停止返回按钮事件,不是吗?

我是否必须编写自己的后退按钮并将其设置为leftBarButtonItem?或者有人有好主意吗? :-)

感谢您的帮助!

【问题讨论】:

标签: iphone ios uinavigationcontroller


【解决方案1】:

我来自另一个线程的answer 匹配这个问题。所以我在这里转发:

我已经实现了UIViewController-BackButtonHandler 扩展。它不需要继承任何东西,只需将其放入您的项目中并覆盖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.

【讨论】:

  • 遗憾的是,我们现在在 iOS 8 中,仍然需要这个出色的代码来拦截后退按钮操作。出色的解决方案,可惜 Apple 没有提供开箱即用的功能。
  • 这不是私有API吗?您是否设法在商店中发布了该应用?
  • 哪里有私有API使用?
  • 这个答案是一种艺术的和平!
  • 此扩展与 Swift 4 完美配合。非常感谢。 here is the swift 3 version of the extention,如果有人需要
【解决方案2】:

您需要做的是使用导航栏的委托,而不是导航控制器。

- (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;

【讨论】:

  • 我的导航栏由导航控制器管理,并且手动将栏的委托设置为我的视图控制器会导致异常,说明不允许在导航栏上手动设置委托,如果bar 由导航控制器管理。
  • 只是 UINavigationController 的子类,然后覆盖 - (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item;
  • Enzo,Apple 不允许继承 UINavigationController:stackoverflow.com/questions/1937616/…
  • 文档说它“不适合子类化”,但它并不禁止你这样做。我一直在我的许多应用程序中继承 UINavigationController 没有问题,其他许多人也是如此。
  • 显然 UINavigationBarDelegate 方法是私有的,因此如果我尝试调用 [super navigationBar:navigationBar shouldPopItem:item] 来获取默认行为,则会出现编译错误“'UINavigationController' 没有可见的@interface”声明选择器'navigationBar:shouldPopItem:'"。有什么合法的解决办法吗?
【解决方案3】:

viewWillDisappear 是视图将要消失的事件的委托方法 - 开发人员对此无能为力!如果可以的话,它会是一个viewShouldDisappear 委托方法。

所以我想唯一的方法就是按照你的建议,使用自定义 leftBarButtonItem

【讨论】:

    【解决方案4】:

    我必须说这是 Apple 似乎并不容易做到的常见用例之一,我看到很多努力都试图让它发挥作用。我想也许我应该在这里总结一下我的发现。

    正如许多人所指出的,UINavigationBarDelegate 中的以下方法是实现此功能的关键。

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

    许多子类化了UINavigationController 并实现了上述方法,使其易于使用,无需直接访问UINavigationBar

    很遗憾,仍然存在一些问题。

    • 向后滑动手势不会调用此方法。
    • 虽然看起来有必要,但在此方法中调用 popViewControllerAnimated: 时会报告崩溃。
    • 取消弹出后,后退按钮保持灰显。

    向后滑动手势

    我们需要像 https://stackoverflow.com/a/23173035/2400328 那样设置委托来拦截手势。

    如果 UINavigationController 是子类,那将是:

    self.interactivePopGestureRecognizer.delegate = self
    

    和实施:

    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
    

    修改委托属性时要小心,因为在调用初始化程序后它会被修改。

    没有打电话给popViewControllerAnimated:

    虽然没有记录,但可以避免调用 popViewControllerAnimated:,就像在 https://stackoverflow.com/a/26084150/2400328 中一样。

    它涉及调用UINavigationController 中的navigationBar:shouldPopItem:(来自子类)。

    返回按钮

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

    你只需要设置一个属性YES和NO。

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

    【讨论】:

      【解决方案5】:

      您可以使用带有图形的自定义按钮,该按钮看起来与“后退”按钮完全相同,并使用此图形创建自定义 leftBarButtonItem 视图作为UIButton。使用自定义back: 选择器将目标self 添加到您的按钮并在那里弹出您的警报。如果用户按“是”退出关闭此视图控制器,如果不是 - 什么也不做。这里的技巧是按钮看起来与导航栏的后退按钮完全一样。

      【讨论】:

        【解决方案6】:

        如果您制作自己的后退按钮并将其设置为导航控制器的左按钮,那就更好了。这绝对可以帮助您执行任何操作

        【讨论】:

          【解决方案7】:

          如果您正在寻找在 iOS 10 上的 Swift 中执行此操作的方法,您可以创建一个自定义 UINavigationController,然后创建一个 UINavigationBarDelegate 扩展:

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

          【讨论】:

          • 在 iOS 14.2 测试版上无法正常工作。分裂。我想我们必须以某种方式调用超级实现。
          【解决方案8】:

          方法

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

          正在做你想做的事。不幸的是,我们不应该将 UINavigationBar 委托给我们自己的对象:(

          Apple Documentation 声明:

          ... 此外,导航控制器对象会自动将自己指定为其 UINavigationBar 对象的委托,并防止其他对象更改该关系。 ...

          一个/那个?做你想做的事的方法是放入你自己的后退按钮。 在该方法中,您进行测试并调用

          [self.navigationController popViewControllerAnimated:true];
          

          如果允许用户返回。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-01-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-04-09
            • 2011-05-04
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多