检测导航栏上按下“后退”button的时间

在导航栏上按下后退button(返回到前一个屏幕,返回到父视图)时,我需要执行一些操作。

是否有一些方法可以实现捕捉事件并启动一些操作,以在屏幕消失之前暂停和保存数据?

自iOS 5以来,我发现处理这种情况的最简单方法是使用新方法- (BOOL)isMovingFromParentViewController

 - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.isMovingFromParentViewController) { // Do your stuff here } } 

- (BOOL)isMovingFromParentViewController是有道理的,当你推动和popup导航堆栈中的控制器。

但是,如果你正在展示模态视图控制器,你应该使用- (BOOL)isBeingDismissed来代替:

 - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.isBeingDismissed) { // Do your stuff here } } 

正如在这个问题中所指出的,你可以结合这两个属性:

 - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.isMovingFromParentViewController || self.isBeingDismissed) { // Do your stuff here } } 

其他解决scheme依赖于UINavigationBar的存在。 我更喜欢这种方法,因为它将所需的任务从触发事件的操作中解耦出来,即按下后退button。

虽然viewWillAppear()viewDidDisappear() 点击后退button时调用,但是在其他时候也会调用它们。 查看更多答案的结尾。

父视图控制器

当使用willMoveToParentViewController(_:)或者didMoveToParentViewController()将VC从父级(NavigationController)中移除时,检测后退button会更好。

如果父母为零,则视图控制器正从导航堆栈popup并被解散。 如果父母不是零,则将其添加到堆栈并呈现。

 // Objective-C -(void)willMoveToParentViewController:(UIViewController *)parent { [super willMoveToParentViewController:parent]; if (!parent){ // The back button was pressed or interactive gesture used } } // Swift override func willMove(toParentViewController parent: UIViewController?) { super.willMove(toParentViewController:parent) if parent == nil { // The back button was pressed or interactive gesture used } } 

在视图控制器被解散后,将交换为willMove for didMove并检查self.parent以执行工作。

停止解雇(asynchronous)

请注意,如果您需要执行某种asynchronous保存,检查父代不允许您“暂停”转换。 要做到这一点,你可以实现以下内容。 唯一的缺点是你失去了花哨的iOS风格/animation后退button。 在这里也要小心交互式滑动手势。 使用以下来处理这种情况。

 var backButton : UIBarButtonItem! override func viewDidLoad() { super.viewDidLoad() // Disable the swipe to make sure you get your chance to save self.navigationController?.interactivePopGestureRecognizer.enabled = false // Replace the default back button self.navigationItem.setHidesBackButton(true, animated: false) self.backButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Plain, target: self, action: "goBack") self.navigationItem.leftBarButtonItem = backButton } // Then handle the button selection func goBack() { // Here we just remove the back button, you could also disabled it or better yet show an activityIndicator self.navigationItem.leftBarButtonItem = nil someData.saveInBackground { (success, error) -> Void in if success { self.navigationController?.popViewControllerAnimated(true) // Don't forget to re-enable the interactive gesture self.navigationController?.interactivePopGestureRecognizer.enabled = true } else { self.navigationItem.leftBarButtonItem = self.backButton // Handle the error } } } 

会出现更多/将会出现

如果你没有得到viewWillAppear viewDidDisappear问题,让我们通过一个例子。 假设你有三个视图控制器:

  1. ListVC: 事物的表格视图
  2. DetailVC: 关于事物的细节
  3. SettingsVC: 一些东西的选项

当你从listVCsettingsVC并返回到listVC让我们按照detailVC上的调用

列表>细节 (push detailVC) Detail.viewDidAppear < – 出现
细节>设置 (推送设置Detail.viewDidDisappearDetail.viewDidDisappear < – 消失

而当我们回去…
设置>细节 (popup设置Detail.viewDidAppearDetail.viewDidAppear < – 出现
Detail> List (pop detailVC) Detail.viewDidDisappear < – 消失

请注意, viewDidDisappear被多次viewDidDisappear ,不仅在返回时,还在向前时。 对于一个可能需要的快速操作,但对于一个更复杂的操作,如networking调用来保存,它可能不会。

第一种方法

 - (void)didMoveToParentViewController:(UIViewController *)parent { if (![parent isEqual:self.parentViewController]) { NSLog(@"Back pressed"); } } 

第二种方法

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

我已经打了两天这个问题了(或者说打架)。 IMO最好的办法就是创build一个扩展类和一个协议,像这样:

 @protocol UINavigationControllerBackButtonDelegate <NSObject> /** * Indicates that the back button was pressed. * If this message is implemented the pop logic must be manually handled. */ - (void)backButtonPressed; @end @interface UINavigationController(BackButtonHandler) @end @implementation UINavigationController(BackButtonHandler) - (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item { UIViewController *topViewController = self.topViewController; BOOL wasBackButtonClicked = topViewController.navigationItem == item; SEL backButtonPressedSel = @selector(backButtonPressed); if (wasBackButtonClicked && [topViewController respondsToSelector:backButtonPressedSel]) { [topViewController performSelector:backButtonPressedSel]; return NO; } else { [self popViewControllerAnimated:YES]; return YES; } } @end 

这是有效的,因为UINavigationController将接收到对navigationBar:shouldPopItem:的调用navigationBar:shouldPopItem:每当视图控制器被popup时。 在那里,我们检测是否按下了(任何其他button)。 你唯一需要做的是在视图控制器里按下后面的地方实现协议。

记得手动popup视图控制器里面backButtonPressedSel ,如果一切正常。

如果你已经有了子类UINavigationViewController并且实现了navigationBar:shouldPopItem:不用担心,这不会干扰它。

您可能也有兴趣禁用后面的手势。

 if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.enabled = NO; } 

这在Swift中适用于iOS 9.3.x:

 override func didMoveToParentViewController(parent: UIViewController?) { super.didMoveToParentViewController(parent) if parent == self.navigationController?.parentViewController { print("Back tapped") } } 

不同于这里的其他解决scheme,这似乎并不意外触发。

为了logging,我认为这是他正在寻找的更多…

  UIBarButtonItem *l_backButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRewind target:self action:@selector(backToRootView:)]; self.navigationItem.leftBarButtonItem = l_backButton; - (void) backToRootView:(id)sender { // Perform some custom code [self.navigationController popToRootViewControllerAnimated:YES]; } 

正如purrrminator所说, purrrminator的回答并不完全正确,因为即使以编程方式popup控制器,也会执行your stuff

我迄今为止find的解决scheme并不是很好,但是对我来说很有用。 除了elitalon说的,我也检查我是否以编程方式popup:

 - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if ((self.isMovingFromParentViewController || self.isBeingDismissed) && !self.isPoppingProgrammatically) { // Do your stuff here } } 

您必须将该属性添加到您的控制器,并在以编程方式popup之前将其设置为YES:

 self.isPoppingProgrammatically = YES; [self.navigationController popViewControllerAnimated:YES]; 

谢谢你的帮助!

最好的方法是使用UINavigationController委托方法

 - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated 

使用这个你可以知道什么控制器显示UINavigationController。

 if ([viewController isKindOfClass:[HomeController class]]) { NSLog(@"Show home controller"); } 

对于使用UINavigationController的Swift:

 override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) if self.navigationController?.topViewController != self { print("back button tapped") } } 

7ynk3r的答案非常接近我最终使用的内容,但是它需要一些调整:

 - (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item { UIViewController *topViewController = self.topViewController; BOOL wasBackButtonClicked = topViewController.navigationItem == item; if (wasBackButtonClicked) { if ([topViewController respondsToSelector:@selector(navBackButtonPressed)]) { // if user did press back on the view controller where you handle the navBackButtonPressed [topViewController performSelector:@selector(navBackButtonPressed)]; return NO; } else { // if user did press back but you are not on the view controller that can handle the navBackButtonPressed [self popViewControllerAnimated:YES]; return YES; } } else { // when you call popViewController programmatically you do not want to pop it twice return YES; } } 

你应该看看UINavigationBarDelegate协议 。 在这种情况下,您可能需要使用navigationBar:shouldPopItem:方法。

正如Coli88所说,你应该检查UINavigationBarDelegate协议。

更一般的方式,当当前可见的视图控制器保留的视图即将消失时,也可以使用- (void)viewWillDisapear:(BOOL)animated来执行自定义工作。 不幸的是,这将包括打扰推动和stream行的情况。

我已经解决了这个问题,通过添加一个UIControl左侧的导航栏。

 UIControl *leftBarItemControl = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, 90, 44)]; [leftBarItemControl addTarget:self action:@selector(onLeftItemClick:) forControlEvents:UIControlEventTouchUpInside]; self.leftItemControl = leftBarItemControl; [self.navigationController.navigationBar addSubview:leftBarItemControl]; [self.navigationController.navigationBar bringSubviewToFront:leftBarItemControl]; 

你需要记住当视图消失时将其删除:

 - (void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.leftItemControl) { [self.leftItemControl removeFromSuperview]; } } 

就这样!

您可以使用后退buttoncallback,如下所示:

 - (BOOL) navigationShouldPopOnBackButton { [self backAction]; return NO; } - (void) backAction { // your code goes here // show confirmation alert, for example // ... } 

self.navigationController.isMovingFromParentViewController无法在iOS8和9上使用:

 -(void) viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (self.navigationController.topViewController != self) { // Is Popping } } 

(迅速)

finalyfind解决scheme..我们正在寻找的方法是“willShowViewController”这是UINavigationController的委托方法

 //IMPORT UINavigationControllerDelegate !! class PushedController: UIViewController, UINavigationControllerDelegate { override func viewDidLoad() { //set delegate to current class (self) navigationController?.delegate = self } func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) { //MyViewController shoud be the name of your parent Class if var myViewController = viewController as? MyViewController { //YOUR STUFF } } }