63

我需要知道我的视图控制器何时将从导航堆栈中弹出,以便我可以执行操作。

我不能使用 -viewWillDisappear,因为当视图控制器出于任何原因移出屏幕时会调用它(比如将新的视图控制器推到顶部)。

我特别需要知道控制器何时会自行弹出。

任何想法都会很棒,在此先感谢。

4

15 回答 15

87

覆盖viewWillDisappear提供的 VC 中的方法,然后检查isMovingFromParentViewController覆盖中的标志并执行特定逻辑。就我而言,我隐藏了导航控制器工具栏。仍然需要您介绍的 VC 了解它是被推动的,尽管它并不完美。

于 2012-03-07T15:23:41.357 回答
31

幸运的是,当 viewWillDisappear 方法被调用时,viewController 已经从堆栈中移除了,所以我们知道 viewController 正在弹出,因为它不再在self.navigationController.viewControllers中

斯威夫特 4

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    if let nav = self.navigationController {
        let isPopping = !nav.viewControllers.contains(self)
        if isPopping {
            // popping off nav
        } else {
            // on nav, not popping off (pushing past, being presented over, etc.)
        }
    } else {
        // not on nav at all
    }
}

原始代码

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    if ((self.navigationController) && 
        (![self.navigationController.viewControllers containsObject:self])) {
        NSLog(@"I've been popped!");
    }
}
于 2013-06-29T19:54:26.327 回答
26

尝试在您的自定义子类中覆盖willMoveToParentViewController:(而不是) .viewWillDisappear:UIViewController

在从容器视图控制器中添加或删除视图控制器之前调用。

- (void)willMoveToParentViewController:(UIViewController *)parent
{
    [super willMoveToParentViewController:parent];
    if (!parent) {
        // `self` is about to get popped.
    }
}
于 2013-10-25T05:04:46.390 回答
15

我认为没有明确的消息,但您可以继承 UINavigationController 并覆盖 - popViewControllerAnimated(尽管我自己之前没有尝试过)。

或者,如果没有其他对视图控制器的引用,您可以添加到它的-dealloc 吗?

于 2009-03-13T12:00:13.383 回答
14

这对我有用。

- (void)viewDidDisappear:(BOOL)animated
{
    if (self.parentViewController == nil) {
        NSLog(@"viewDidDisappear doesn't have parent so it's been popped");
        //release stuff here
    } else {
        NSLog(@"PersonViewController view just hidden");
    }
}
于 2010-02-10T01:15:41.127 回答
9

你可以在这里抓住它。

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

    if (viewController == YourAboutToAppearController) {
            // do something
    }
}

这将在新视图显示之前触发。还没有人动。我一直在 asinine NavigationController 前做魔术。您可以设置标题和按钮标题并在那里做任何事情。

于 2009-05-03T08:18:55.263 回答
3

我也有同样的问题。我尝试使用 viewDisDisappear,但我没有调用该函数 :((不知道为什么,可能是因为我所有的 VC 都是 UITableViewController)。Alex 的建议工作正常,但如果您的导航控制器显示在更多选项卡。在这种情况下,您的导航控制器的所有 VC 的导航控制器都为 UIMoreNavigationController,而不是您已子类化的导航控制器,因此当 VC 即将弹出时,导航不会通知您。
最后,我解决了问题使用 UINavigationController 的类别,只需重写 - (UIViewController *)popViewControllerAnimated:(BOOL)animated

- (UIViewController *)popViewControllerAnimated:(BOOL)animated{
   NSLog(@"UINavigationController(Magic)");
   UIViewController *vc = self.topViewController;
   if ([vc respondsToSelector:@selector(viewControllerWillBePopped)]) {
      [vc performSelector:@selector(viewControllerWillBePopped)];
   }
   NSArray *vcs = self.viewControllers;
   UIViewController *vcc = [vcs objectAtIndex:[vcs count] - 2];
   [self popToViewController:vcc animated:YES];
   return vcc;}

它对我很有效:D

于 2010-09-18T04:18:13.023 回答
2

我试过这个:

- (void) viewWillDisappear:(BOOL)animated {
    // If we are disappearing because we were removed from navigation stack
    if (self.navigationController == nil) {
        // YOUR CODE HERE
    }

    [super viewWillDisappear:animated];
}

这个想法是在弹出时,视图控制器的 navigationController 设置为 nil。因此,如果视图要消失,并且它不再有一个导航控制器,我得出的结论是它被弹出了。(在其他情况下可能不起作用)。

不能保证 viewWillDisappear 会在弹出时被调用,因为文档中没有提到它。当视图是顶视图和顶视图下方时,我尝试了它 - 它在两者中都有效。

祝你好运,奥德。

于 2011-03-31T10:24:57.450 回答
2

子类UINavigationController和覆盖popViewController

斯威夫特 3

protocol CanPreventPopProtocol {
    func shouldBePopped() -> Bool
}
  
class MyNavigationController: UINavigationController {
    override func popViewController(animated: Bool) -> UIViewController? {
        let viewController = self.topViewController
        
        if let canPreventPop = viewController as? CanPreventPopProtocol {
            if !canPreventPop.shouldBePopped() {
                return nil
            }
        }
        return super.popViewController(animated: animated)
    }

    //important to prevent UI thread from freezing
    //
    //if popViewController is called by gesture recognizer and prevented by returning nil
    //UI will freeze after calling super.popViewController
    //so that, in order to solve the problem we should not return nil from popViewController
    //we interrupt the call made by gesture recognizer to popViewController through
    //returning false on gestureRecognizerShouldBegin
    //
    //tested on iOS 9.3.2 not others
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        let viewController = self.topViewController
        
        if let canPreventPop = viewController as? CanPreventPopProtocol {
            if !canPreventPop.shouldBePopped() {
                return false
            }
        }
        
        return true
    }

}
于 2017-01-28T17:00:57.977 回答
1

你可以使用这个:

if(self.isMovingToParentViewController)
{
    NSLog(@"Pushed");
}
else
{
    NSLog(@"Popped");
}
于 2015-07-03T07:51:29.113 回答
0

也许你可以使用 UINavigationBarDelegate 的 navigationBar:shouldPopItem 协议方法。

于 2009-03-13T20:43:57.023 回答
0

尝试在 viewwilldisappear 中进行此检查 if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) { //这个视图的弹出已经发生。}

于 2014-02-21T08:38:31.140 回答
0

我有时还需要防止弹出,所以对我来说最好的答案是由 Orkhan Alikhanov 写的。但是因为没有设置delegate所以不起作用,所以我做了最终版本:

import UIKit

class CustomActionsNavigationController: UINavigationController, 
                                         UIGestureRecognizerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    override func popViewController(animated: Bool) -> UIViewController? {
        if let delegate = topViewController as? CustomActionsNavigationControllerDelegate {
            guard delegate.shouldPop() else { return nil }
        }
        return super.popViewController(animated: animated)
    }

    // important to prevent UI thread from freezing
    //
    // if popViewController is called by gesture recognizer and prevented by returning nil
    // UI will freeze after calling super.popViewController
    // so that, in order to solve the problem we should not return nil from popViewController
    // we interrupt the call made by gesture recognizer to popViewController through
    // returning false on gestureRecognizerShouldBegin
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if let delegate = topViewController as? CustomActionsNavigationControllerDelegate {
            if !delegate.shouldPop() {
                return false
            }
        }

        // This if statement prevents navigation controller to pop when there is only one view controller
        if viewControllers.count == 1 {
            return false
        }

        return true
    }
}

protocol CustomActionsNavigationControllerDelegate {
    func shouldPop() -> Bool
}

更新

我添加了viewControllers.count == 1案例,因为如果堆栈中有一个控制器并且用户做出手势,它将冻结您的应用程序的 UI。

于 2019-10-03T07:20:00.657 回答
0

您可以观察通知:

- (void)viewDidLoad{
    [super viewDidLoad];
    [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(navigationControllerWillShowViewController:) name:@"UINavigationControllerWillShowViewControllerNotification" object:nil];
}

- (void)navigationControllerDidShowViewController:(NSNotification *)notification{
    UIViewController *lastVisible = notification.userInfo[@"UINavigationControllerLastVisibleViewController"];
    if(lastVisible == self){
        // we are being popped
    }
}
于 2019-10-05T22:45:04.623 回答
0
- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];

    const BOOL removingFromParent = ![self.navigationController.viewControllers containsObject:self.parentViewController];
    if ( removingFromParent ) {
        // cleanup
    }
}
于 2020-10-24T14:14:53.460 回答