Est-il possible de déterminer si ViewController est présenté comme Modal?

est-il possible de vérifier si la classe inside ViewController est présentée comme contrôleur de vue modale?

113
demandé sur Bo Persson 2010-05-09 22:24:16

14 réponses

depuis modalViewController a été déprécié dans iOS 6, Voici une version qui fonctionne pour iOS 5+ et qui compile sans avertissements.

Objectif-C:

- (BOOL)isModal {
    return self.presentingViewController.presentedViewController == self
      || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
      || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}

Swift:

var isModal: Bool {
    return self.presentingViewController?.presentedViewController == self
        || (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController)
        || self.tabBarController?.presentingViewController is UITabBarController
}

chapeau pour la réponse de Felipe.

95
répondu Gabriele Petronella 2015-04-02 11:09:58

si vous cherchez iOS 6+, cette réponse est dépréciée et vous devez cocher réponse de Gabriele Petronella


il n'y a pas de façon simple de faire cela, comme une propriété ou une méthode native de UIKit. Ce que vous pouvez faire est de vérifier plusieurs aspects de votre contrôleur pour s'assurer qu'il est présenté comme le modal.

ainsi, pour vérifier si le courant (représenté comme self dans le code ci-dessous contrôleur est présenté de manière modale ou non, j'ai la fonction ci-dessous soit dans une catégorie UIViewController , ou (si votre projet n'a pas besoin d'utiliser d'autres contrôleurs UIKit, comme UITableViewController par exemple) dans un contrôleur de base que mes autres contrôleurs héritent de

-(BOOL)isModal {

     BOOL isModal = ((self.parentViewController && self.parentViewController.modalViewController == self) || 
            //or if I have a navigation controller, check if its parent modal view controller is self navigation controller
            ( self.navigationController && self.navigationController.parentViewController && self.navigationController.parentViewController.modalViewController == self.navigationController) || 
            //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
            [[[self tabBarController] parentViewController] isKindOfClass:[UITabBarController class]]);

    //iOS 5+
    if (!isModal && [self respondsToSelector:@selector(presentingViewController)]) {

        isModal = ((self.presentingViewController && self.presentingViewController.modalViewController == self) || 
             //or if I have a navigation controller, check if its parent modal view controller is self navigation controller
             (self.navigationController && self.navigationController.presentingViewController && self.navigationController.presentingViewController.modalViewController == self.navigationController) || 
             //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
             [[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]]);

    }

    return isModal;        

}

EDIT: J'ai ajouté la dernière vérification pour voir si un UITabBarController est utilisé, et vous présentez un autre UITabBarController comme modal.

EDIT 2: Ajouté iOS 5+ check, où UIViewController ne répond plus à parentViewController , mais à presentingViewController à la place.

EDIT 3: j'ai créé un gist juste au cas où https://gist.github.com/3174081

77
répondu Felipe Sabino 2017-05-23 11:54:46

dans iOS5+, comme vous pouvez le voir dans référence de classe UIViewController , vous pouvez l'obtenir à partir de la propriété"presentingViewController".

presentingViewController Le contrôleur de vue qui a présenté ce contrôleur de vue. (en lecture seule)

@property (nonatomic, readonly) UIViewController *presentingViewController

Discussion

Si le contrôleur de vue qui a reçu ce message est présenté par un autre contrôleur de vue, cette propriété contient le contrôleur de vue qui le présente. Si le contrôleur de vue n'est pas présenté, mais qu'un de ses ancêtres est présenté, cette propriété contient le contrôleur de vue présentant l'ancêtre le plus proche. Si ni le contrôleur de vue ni aucun de ses ancêtres ne sont présentés, cette propriété est nulle.

disponibility

Disponible en iOS 5.0 et versions ultérieures.

Déclaré Dans

UIViewController.h

35
répondu Raj 2013-02-07 06:38:44

s'il n'y en a pas, vous pouvez définir une propriété pour cela ( presentedAsModal ) dans votre sous-classe UIViewController et la définir à YES avant de présenter le ViewController comme une vue modale.

childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];

vous pouvez vérifier cette valeur dans votre viewWillAppear override.

je crois qu'il n'y a pas de propriété officielle qui indique comment la vue est présentée, mais rien ne vous empêche de créer votre propre.

17
répondu hpique 2010-05-09 18:36:16

Petronella la réponse de ne fonctionne pas si l'auto.navigationController est présenté de façon modulaire, mais self n'est pas égal à self.navigationController.viewControllers[0], dans ce cas, l'auto est poussé.

Voici comment vous pouvez résoudre le problème.

return self.presentingViewController.presentedViewController == self
            || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController && self == self.navigationController.viewControllers[0])
            || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];

et dans Swift:

return self.presentingViewController?.presentedViewController == self
        || (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController && self.navigationController?.viewControllers[0] == self)
        || self.tabBarController?.presentingViewController is UITabBarController
8
répondu Semih Cihan 2017-05-23 10:31:13

ça devrait marcher.

if(self.parentViewController.modalViewController == self)…
6
répondu kubi 2010-05-09 18:47:38

meilleure façon de vérifier

 if (self.navigationController.presentingViewController) {
         NSLog(@"Model Present");
    }
5
répondu Sunny Shah 2013-12-30 05:40:20

si vous n'avez pas besoin de faire la distinction entre les vues modales plein écran et les vues non modales, ce qui est le cas dans mon projet (je m'occupais d'un problème qui se produit seulement avec les feuilles de forme et les feuilles de page), vous pouvez utiliser la propriété modalPresentationStyle de UIViewController:

switch (self.modalPresentationStyle) {
    case 0: NSLog(@"full screen, or not modal"); break;
    case 1: NSLog(@"page sheet"); break;
    case 2: NSLog(@"form sheet"); break;
}
2
répondu arlomedia 2012-12-08 09:34:28

In Swift :

func isUIViewControllerPresentedAsModal() -> Bool {
    if((self.presentingViewController) != nil) {
        return true
    }

    if(self.presentingViewController?.presentedViewController == self) {
        return true
    }

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

    if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) {
        return true
    }

    return false
}
2
répondu King-Wizard 2015-09-12 21:41:55

dans mon projet, j'ai un contrôleur de vue (Detail) qui peut être présenté soit modalement (lors de l'ajout d'un nouvel élément), soit avec push (lors de l'édition d'un élément existant) par le contrôleur de vue maître. Lorsque l'utilisateur tape [Done], le contrôleur de la vue des détails appelle la méthode du contrôleur de la vue principale pour notifier qu'elle est prête à être fermée. Le maître doit déterminer comment le détail est présenté afin de savoir comment le fermer. C'est comme ça que je fais:

UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
    [self dismissViewControllerAnimated:YES completion:NULL];
} else {
    [self.navigationController popViewControllerAnimated:YES];
}
1
répondu Olex 2015-02-20 20:07:54

un piratage comme celui-ci pourrait marcher.

UIViewController* child = self;
UIViewController* parent = child.parentViewController;
while (parent && parent.modalViewController != child) {
    child = parent;
    parent = child.parentViewController;
}
if (parent) {
    // A view controller in the hierarchy was presented as a modal view controller
}

cependant, je pense que ma réponse précédente est une solution plus propre.

0
répondu hpique 2010-05-10 22:39:59

ce qui a fonctionné pour moi est le suivant:

// this is the trick: set parent view controller as application's window root view controller
UIApplication.sharedApplication.delegate.window.rootViewController = viewController;

// assert no modal view is presented
XCTAssertNil(viewController.presentedViewController);

// simulate button tap which shows modal view controller
[viewController.deleteButton sendActionsForControlEvents:UIControlEventTouchUpInside];

// assert that modal view controller is presented
XCTAssertEqualObjects(viewController.presentedViewController.class, MyModalViewController.class);

autant que je l'ai testé, cela fonctionne pour iOS7 et iOS8. N'a pas essayé sur iOS6 cependant.

0
répondu mixtly87 2014-09-15 07:18:56

j'ai regardé un peu autour pour trouver la bonne réponse à cette question, et je n'ai pas pu en trouver qui couvrait tous les scénarios possibles. J'ai écrit ces quelques lignes de code qui semblent faire le travail. Vous pouvez trouver peu de commentaires en ligne pour comprendre ce qui a été vérifié.

- (BOOL)isModal {
    BOOL modal = NO;
    if ([self presentingViewController]) { //Some view Controller is presenting the current stack
        UIViewController *presented = [[self presentingViewController] presentedViewController]; // What's been presented
        if ([presented respondsToSelector:@selector(viewControllers)]) { // There's a stack
            NSArray *viewControllers = [presented performSelector:@selector(viewControllers)];
            modal = [viewControllers firstObject] == self; // Current VC is presented modally if it's the first in the stack
        }
        else {
            modal = presented == self; // Don't think this is actually needed. set modal = YES should do the job tho.
        }
    }
    return modal;
}

Espérons que cette aide.

0
répondu DennyLou 2015-07-16 12:12:51

voici ma version modifiée de @GabrielePetronella isModal , qui fonctionne avec les contrôleurs de vue contenue en ce sens qu'il remonte d'abord la hiérarchie du contrôleur parent viewcontroller. J'ai aussi sorti le code en plusieurs lignes pour que ce soit clair.

var isModal: Bool {
    // If we are a child view controller, we need to check our parent's presentation
    // rather than our own.  So walk up the chain until we don't see any parentViewControllers
    var potentiallyPresentedViewController : UIViewController = self
    while (potentiallyPresentedViewController.parentViewController != nil) {
        potentiallyPresentedViewController = potentiallyPresentedViewController.parentViewController!
    }

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

    if let navigationController = potentiallyPresentedViewController.navigationController {
        if navigationController.presentingViewController?.presentedViewController == navigationController {
            return true
        }
    }

    return potentiallyPresentedViewController.tabBarController?.presentingViewController is UITabBarController
}
0
répondu Ryan 2017-05-23 12:10:08