设置导航控制器中后退按钮的操作

Par*_*ots 177 iphone cocoa-touch uinavigationcontroller uibarbuttonitem ios

我正在尝试覆盖导航控制器中后退按钮的默认操作.我已经在自定义按钮上提供了一个目标操作.奇怪的是,当通过backbutton属性分配它时,它不会注意它们,它只是弹出当前视图并返回到根:

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] 
                                  initWithTitle: @"Servers" 
                                  style:UIBarButtonItemStylePlain 
                                  target:self 
                                  action:@selector(home)];
self.navigationItem.backBarButtonItem = backButton;
Run Code Online (Sandbox Code Playgroud)

当我把它通过leftBarButtonItemnavigationItem调用我的动作,但是那么按钮看起来像一个普通的圆而不是一个带箭头的后面一个:

self.navigationItem.leftBarButtonItem = backButton;
Run Code Online (Sandbox Code Playgroud)

在返回根视图之前,如何让它调用我的自定义操作?有没有办法覆盖默认的后退操作,还是有一种方法在离开视图时总是被调用(viewDidUnload不这样做)?

Wil*_*sch 363

尝试将其放入要检测印刷机的视图控制器中:

-(void) viewWillDisappear:(BOOL)animated {
    if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
       // back button was pressed.  We know this is true because self is no longer
       // in the navigation stack.  
    }
    [super viewWillDisappear:animated];
}
Run Code Online (Sandbox Code Playgroud)

  • 另一个问题是,如果用户按下后退按钮或者以编程方式调用[self.navigationController popViewControllerAnimated:YES],则无法区分 (21认同)
  • 只是一个FYI:Swift版本:`if(find(self.navigationController!.viewControllers as![UIViewController],self)== nil)` (8认同)
  • +1很棒的黑客,但不提供对流行音乐的控制 (6认同)
  • 谢谢 - 直观,简单,有效! (3认同)
  • 如果我通过一个按钮向代表发送消息并且委托弹出控制器,这对我不起作用 - 这仍然会触发. (3认同)

one*_*ray 175

我已经实现了UIViewController-BackButtonHandler扩展.它不需要子类化任何东西,只需将它放入您的项目并navigationShouldPopOnBackButtonUIViewController类中重写方法:

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

下载示例应用.

  • 这是我见过的最干净的解决方案,比使用自己的自定义UIButton更好,更简单.谢谢! (16认同)
  • 我刚刚在iOS 7.1中实现了这个(相当酷的BTW),并注意到在返回"NO"后,后退按钮保持在禁用状态(视觉上,因为它仍然接收并对触摸事件作出反应).我通过在`shouldPop`检查中添加`else`语句并在导航栏子视图中循环来解决它,并在动画块内部将`alpha`值设置回1:https://gist.github. COM/idevsoftware/9754057 (8认同)
  • `navigationBar:shouldPopItem:`不是私有方法,因为它是`UINavigationBarDelegate`协议的一部分. (3认同)
  • 这是我见过的最好的延伸之一.非常感谢. (2认同)

Han*_*ers 42

与Amagrammer说的不同,这是可能的.你必须继承你的navigationController.我在这里解释了一切(包括示例代码).


kga*_*dis 13

Swift版本:

(/sf/answers/1339301701/)

在视图控制器中,您只需遵循协议并执行您需要的任何操作:

extension MyViewController: NavigationControllerBackButtonDelegate {
    func shouldPopOnBackButtonPress() -> Bool {
        performSomeActionOnThePressOfABackButton()
        return false
    }
}
Run Code Online (Sandbox Code Playgroud)

然后创建一个类,比如说NavigationController+BackButton,只需复制粘贴下面的代码:

protocol NavigationControllerBackButtonDelegate {
    func shouldPopOnBackButtonPress() -> Bool
}

extension UINavigationController {
    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        // Prevents from a synchronization issue of popping too many navigation items
        // and not enough view controllers or viceversa from unusual tapping
        if viewControllers.count < navigationBar.items!.count {
            return true
        }

        // Check if we have a view controller that wants to respond to being popped
        var shouldPop = true
        if let viewController = topViewController as? NavigationControllerBackButtonDelegate {
            shouldPop = viewController.shouldPopOnBackButtonPress()
        }

        if (shouldPop) {
            DispatchQueue.main.async {
                self.popViewController(animated: true)
            }
        } else {
            // Prevent the back button from staying in an disabled state
            for view in navigationBar.subviews {
                if view.alpha < 1.0 {
                    UIView.animate(withDuration: 0.25, animations: {
                        view.alpha = 1.0
                    })
                }
            }

        }

        return false
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 也不为我工作。永远不会调用 shouldPop 方法。您是否在某处设置了代表? (2认同)

Ale*_*lds 5

不可能直接做.有几种选择:

  1. 创建自己的自定义UIBarButtonItem,如果测试通过,则自动调整并弹出
  2. 使用UITextField委托方法验证表单字段内容,例如-textFieldShouldReturn:,在键盘上按下ReturnDone按钮后调用该方法

第一个选项的缺点是无法从自定义栏按钮访问后退按钮的左指箭头样式.因此,您必须使用图像或使用常规样式按钮.

第二个选项很好,因为您在委托方法中返回了文本字段,因此您可以将验证逻辑定位到发送给委托回调方法的特定文本字段.


psy*_*cho 5

由于某些线程原因,@ HansPinckaers提到的解决方案不适合我,但我找到了一种更简单的方法来触摸后退按钮,我想把它固定在这里,以防这可以避免数小时的欺骗其他人.诀窍很简单:只需将透明的UIButton添加为UINavigationBar的子视图,并为他设置选择器,就像它是真正的按钮一样!这是使用Monotouch和C#的一个例子,但是对objective-c的翻译不应该太难找到.

public class Test : UIViewController {
    public override void ViewDidLoad() {
        UIButton b = new UIButton(new RectangleF(0, 0, 60, 44)); //width must be adapted to label contained in button
        b.BackgroundColor = UIColor.Clear; //making the background invisible
        b.Title = string.Empty; // and no need to write anything
        b.TouchDown += delegate {
            Console.WriteLine("caught!");
            if (true) // check what you want here
                NavigationController.PopViewControllerAnimated(true); // and then we pop if we want
        };
        NavigationController.NavigationBar.AddSubview(button); // insert the button to the nav bar
    }
}
Run Code Online (Sandbox Code Playgroud)

有趣的事实:出于测试目的并为我的假按钮找到好尺寸,我将其背景颜色设置为蓝色......并且它显示后退按钮后面!无论如何,它仍然捕获任何触摸目标原始按钮.


Mel*_*emi 2

我不相信这是可能的、容易的。我认为解决这个问题的唯一方法是制作您自己的后退按钮箭头图像并将其放置在那里。起初这让我很沮丧,但我明白为什么为了保持一致性,它被排除在外。

您可以通过创建常规按钮并隐藏默认后退按钮来接近(没有箭头):

self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:@"Servers" style:UIBarButtonItemStyleDone target:nil action:nil] autorelease];
self.navigationItem.hidesBackButton = YES;
Run Code Online (Sandbox Code Playgroud)

  • 是的,问题是我希望它看起来像正常的后退按钮,只需要它先调用我的自定义操作...... (2认同)