web-dev-qa-db-fra.com

Vérifier si le contrôleur de vue est présenté sous forme modale ou s'il est placé sur une pile de navigation

Comment puis-je, dans mon code de contrôleur de vue, différencier entre:

  • présenté modalement
  • poussé sur la pile de navigation

presentingViewController et isMovingToParentViewController sont YES dans les deux cas, ils ne sont donc pas très utiles.

Ce qui complique les choses, c’est que mon contrôleur de vue parent est parfois modal, sur lequel le contrôleur de vue à vérifier est poussé.

Il se trouve que mon problème est d’incorporer ma HtmlViewController dans une UINavigationController qui est ensuite présentée. C'est pourquoi mes propres tentatives et les bonnes réponses ci-dessous ne fonctionnaient pas.

HtmlViewController*     termsViewController = [[HtmlViewController alloc] initWithDictionary:dictionary];
UINavigationController* modalViewController;

modalViewController = [[UINavigationController alloc] initWithRootViewController:termsViewController];
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:modalViewController
                   animated:YES
                 completion:nil];

Je suppose que je ferais mieux de dire à mon contrôleur de vue quand il est modal, au lieu d'essayer de déterminer.

91
meaning-matters

Prendre avec un grain de sel, n'a pas testé.

- (BOOL)isModal {
     if([self presentingViewController])
         return YES;
     if([[[self navigationController] presentingViewController] presentedViewController] == [self navigationController])
         return YES;
     if([[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]])
         return YES;

    return NO;
 }
113
ColdLogic

Vous avez négligé une méthode: isBeingPresented.

isBeingPresented est vrai lorsque le contrôleur de vue est présenté et faux lorsqu'il est poussé.

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if ([self isBeingPresented]) {
        // being presented
    } else if ([self isMovingToParentViewController]) {
        // being pushed
    } else {
        // simply showing again because another VC was dismissed
    }
}
65
rmaddy

Dans Swift :

// MARK: - UIViewController implementation

extension UIViewController {

    var isModal: Bool {

        let presentingIsModal = presentingViewController != nil
        let presentingIsNavigation = navigationController?.presentingViewController?.presentedViewController == navigationController
        let presentingIsTabBar = tabBarController?.presentingViewController is UITabBarController

        return presentingIsModal || presentingIsNavigation || presentingIsTabBar || false
    }
}
57
King-Wizard

self.navigationController! = nil voudrait dire que c'est dans une navigation empiler.

Afin de gérer le cas où le contrôleur de vue actuel est poussé alors que le contrôleur de navigation est présenté sous forme modale, j'ai ajouté quelques lignes de code pour vérifier si le contrôleur de vue actuel est le contrôleur racine dans la pile de navigation.

extension UIViewController{
func isModal() -> Bool {

    if let navigationController = self.navigationController{
        if navigationController.viewControllers.first != self{
            return false
        }
    }

    if self.presentingViewController != nil {
        return true
    }

    if self.navigationController?.presentingViewController?.presentedViewController == self.navigationController  {
        return true
    }

    if self.tabBarController?.presentingViewController is UITabBarController {
        return true
    }

    return false
   }
}
18
Jibeex

Swift 3
Voici une solution qui résout le problème mentionné dans les réponses précédentes, lorsque isModal() renvoie true si poussé UIViewController se trouve dans une pile UINavigationController présentée.

extension UIViewController {
    var isModal: Bool {
        if let index = navigationController?.viewControllers.index(of: self), index > 0 {
            return false
        } else if presentingViewController != nil {
            return true
        } else if navigationController?.presentingViewController?.presentedViewController == navigationController  {
            return true
        } else if tabBarController?.presentingViewController is UITabBarController {
            return true
        } else {
            return false
        }
    }
}

Cela fonctionne pour moi jusqu'à présent ... Si quelques optimisations, merci de les partager.

17
Jonauz

Swift 4

var isModal: Bool {
    return presentingViewController != nil ||
           navigationController?.presentingViewController?.presentedViewController === navigationController ||
           tabBarController?.presentingViewController is UITabBarController
}
12
Charlton Provatas

Comme beaucoup de gens le suggèrent ici, les méthodes de "vérification" ne fonctionnent pas bien dans tous les cas, dans mon projet, j'ai trouvé une solution permettant de gérer cela manuellement .. Ce n'est pas ce qui se passe en coulisses et il faut l'introspection.

DEViewController.h fichier:

#import <UIKit/UIKit.h>

// it is a base class for all view controllers within a project
@interface DEViewController : UIViewController 

// specify a way viewcontroller, is presented  by another viewcontroller
// the presented view controller should manually assign the value to it
typedef NS_ENUM(NSUInteger, SSViewControllerPresentationMethod) {
    SSViewControllerPresentationMethodUnspecified = 0,
    SSViewControllerPresentationMethodPush,
    SSViewControllerPresentationMethodModal,
};
@property (nonatomic) SSViewControllerPresentationMethod viewControllerPresentationMethod;

// other properties/methods...
@end

Les présentations peuvent maintenant être gérées de la manière suivante:

poussé sur la pile de navigation:

// DETestViewController inherits from DEViewController
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodPush;
[self.navigationController pushViewController:vc animated:YES];

présenté modalement avec navigation:

DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
UINavigationController *nav = [[UINavigationController alloc]
                               initWithRootViewController:vc];
[self presentViewController:nav animated:YES completion:nil];

présenté sous forme modale:

DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
[self presentViewController:vc animated:YES completion:nil];

De plus, dans DEViewController, nous pourrions ajouter un repli à "vérifier" si la propriété susmentionnée est égale à SSViewControllerPresentationMethodUnspecified:

- (BOOL)isViewControllerPushed
{
    if (self.viewControllerPresentationMethod != SSViewControllerPresentationMethodUnspecified) {
        return (BOOL)(self.viewControllerPresentationMethod == SSViewControllerPresentationMethodPush);
    }

    else {
        // fallback to default determination method
        return (BOOL)self.navigationController.viewControllers.count > 1;
    }
}
3
Yevhen Dubinin

En supposant que tous les viewControllers que vous présentez de manière modale soient enveloppés dans un nouveau navigationController (ce que vous devriez toujours faire de toute façon), vous pouvez ajouter cette propriété à votre VC.

private var wasPushed: Bool {
    guard let vc = navigationController?.viewControllers.first where vc == self else {
        return true
    }

    return false
}
3
Demosthese

self.navigationController != nil voudrait dire que c'est dans une pile de navigation.

2
Daniel

Pour détecter votre contrôleur est poussé ou pas simplement utiliser le code ci-dessous dans n'importe où vous voulez:

if ([[[self.parentViewController childViewControllers] firstObject] isKindOfClass:[self class]]) {

    // Not pushed
}
else {

    // Pushed
}

J'espère que ce code peut aider n'importe qui ...

1
Arash Zeinoddini
if navigationController.presentingViewController != nil {
    // Navigation controller is being presented modally
}
0
Kirill Kudaev

Si vous utilisez ios 5.0 ou une version ultérieure, veuillez utiliser ce code.

-(BOOL)isPresented
{
if ([self isBeingPresented]) {
    // being presented
     return YES;
} else if ([self isMovingToParentViewController]) {
    // being pushed
     return NO;
} else {
    // simply showing again because another VC was dismissed
     return NO;
}

}

0
Shahbaz Abbasi
if let navigationController = self.navigationController, navigationController.isBeingPresented {
    // being presented
}else{
    // being pushed
}
0
mkto