Checking if a UIViewController is about to get Popped from a navigation stack?

后端 未结 15 905
说谎
说谎 2020-12-04 19:17

I need to know when my view controller is about to get popped from a nav stack so I can perform an action.

I can\'t use -viewWillDisappear, because that gets called

相关标签:
15条回答
  • 2020-12-04 19:21

    I needed to also prevent from popping sometimes so the best answer for me was written by Orkhan Alikhanov. But it did not work because the delegate was not set, so I made the final version:

    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
    }
    

    UPDATE

    I have added viewControllers.count == 1 case, because if there is one controller in the stack and user makes the gesture, it will freeze the UI of your application.

    0 讨论(0)
  • 2020-12-04 19:24

    You can use this one:

    if(self.isMovingToParentViewController)
    {
        NSLog(@"Pushed");
    }
    else
    {
        NSLog(@"Popped");
    }
    
    0 讨论(0)
  • 2020-12-04 19:25

    Override the viewWillDisappear method in the presented VC, then check the isMovingFromParentViewController flag within the override and do specific logic. In my case I'm hiding the navigation controllers toolbar. Still requires that your presented VC understand that it was pushed though so not perfect.

    0 讨论(0)
  • 2020-12-04 19:26

    Fortunately, by the time the viewWillDisappear method is called, the viewController has already been removed from the stack, so we know the viewController is popping because it's no longer in the self.navigationController.viewControllers

    Swift 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
        }
    }
    

    Original Code

    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        if ((self.navigationController) && 
            (![self.navigationController.viewControllers containsObject:self])) {
            NSLog(@"I've been popped!");
        }
    }
    
    0 讨论(0)
  • 2020-12-04 19:27

    You can catch it here.

    - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    
        if (viewController == YourAboutToAppearController) {
                // do something
        }
    }
    

    This will fire just before the display of the new View. Nobody's moved yet. I use all the time to do magic in front of the asinine NavigationController. You can set titles and button titles and do whatever there.

    0 讨论(0)
  • 2020-12-04 19:30

    This is working for me.

    - (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");
        }
    }
    
    0 讨论(0)
提交回复
热议问题