web-dev-qa-db-fra.com

Vérifier si un UIViewController est sur le point de se faire sauter depuis une pile de navigation?

J'ai besoin de savoir quand mon contrôleur de vue est sur le point de sortir d'une pile de navigation pour pouvoir effectuer une action.

Je ne peux pas utiliser -viewWillDisappear, car cela est appelé lorsque le contrôleur de vue est déplacé hors de l'écran pour N'IMPORTE QUELLE raison (comme un nouveau contrôleur de vue poussé en haut).

J'ai spécifiquement besoin de savoir quand le contrôleur est sur le point d'être sauté.

Toutes les idées seraient géniales, merci d'avance.

56
Jasarien

Je ne pense pas qu'il y ait un message explicite pour cela, mais vous pouvez sous-classer UINavigationController et remplacer - popViewControllerAnimated (bien que je n'ai pas essayé cela avant moi-même).

Sinon, s'il n'y a pas d'autres références au contrôleur de vue, pourriez-vous ajouter à son - dealloc?

11
Tom Elliott

Remplacez la méthode viewWillDisappear dans le VC présenté, puis vérifiez l'indicateur isMovingFromParentViewController dans le remplacement et faites une logique spécifique. Dans mon cas, je cache la barre d'outils des contrôleurs de navigation. Nécessite toujours que votre VC comprenne qu'il a été poussé, donc pas parfait.

77
Jeff Marino

Essayez de remplacer willMoveToParentViewController: (au lieu de viewWillDisappear:) dans votre sous-classe personnalisée de UIViewController.

Appelé juste avant l'ajout ou la suppression du contrôleur de vue d'un contrôleur de vue de conteneur.

- (void)willMoveToParentViewController:(UIViewController *)parent
{
    [super willMoveToParentViewController:parent];
    if (!parent) {
        // `self` is about to get popped.
    }
}
25
ma11hew28

Heureusement, au moment où la méthode viewWillDisappear est appelée, le viewController a déjà été supprimé de la pile, nous savons donc que le viewController apparaît, car il n'est plus dans le 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
    }
}

Code d'origine

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    if ((self.navigationController) && 
        (![self.navigationController.viewControllers containsObject:self])) {
        NSLog(@"I've been popped!");
    }
}
18
caoimghgin

Cela fonctionne pour moi.

- (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");
    }
}
12
Ronald Nepsund

Vous pouvez l'attraper ici.

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

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

Cela se déclenchera juste avant l'affichage de la nouvelle vue. Personne n'a encore bougé. J'utilise tout le temps pour faire de la magie devant l'Asinine NavigationController. Vous pouvez définir des titres et des titres de bouton et faire quoi que ce soit là-bas.

8
dieselmcfadden

J'ai le même problème. J'ai essayé avec viewDisDisappear, mais je n'ai pas la fonction appelée :( (je ne sais pas pourquoi, peut-être parce que tous mes VC est UITableViewController). La suggestion d'Alex fonctionne bien mais elle échoue si votre contrôleur de navigation est affiché sous l'onglet Plus. Dans ce cas, tous les VC de vos contrôleurs nav ont le navigationController comme UIMoreNavigationController, pas le contrôleur de navigation que vous avez sous-classé, donc vous ne serez pas averti par le nav quand un VC est sur le point de surgir.
Finalement, j'ai résolu le problème avec une catégorie de UINavigationController, il suffit de réécrire - (UIViewController *) popViewControllerAnimated: (BOOL) animé

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

Cela fonctionne bien pour moi: D

3
hiepnd

J'ai essayé ceci:

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

L'idée est qu'au popping, la navigationController du contrôleur de vue est définie sur zéro. Donc, si la vue devait disparaître et qu'elle a plus de navigationController, j'ai conclu qu'elle était sautée. (peut ne pas fonctionner dans d'autres scénarios).

Je ne peux pas garantir que viewWillDisappear sera appelé lors du popping, car il n'est pas mentionné dans les documents. Je l'ai essayé lorsque la vue était en vue de dessus et en dessous de la vue de dessus - et cela a fonctionné dans les deux.

Bonne chance, Oded.

2
Oded Ben Dov

Sous-classe UINavigationController et remplacement popViewController:

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

}
1
Orkhan Alikhanov

Vous pouvez utiliser celui-ci:

if(self.isMovingToParentViewController)
{
    NSLog(@"Pushed");
}
else
{
    NSLog(@"Popped");
}
1
itechnician

Essayez de faire cette vérification dans viewwilldisappear if ([self.navigationController.viewControllers indexOfObject: self] == NSNotFound) {// le popping de cette vue s'est produit. }

0
ravoorinandan

Vous pouvez peut-être utiliser la méthode de protocole navigationBar: shouldPopItem d'UINavigationBarDelegate.

0
François P.