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?
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.
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
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
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.
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
ça devrait marcher.
if(self.parentViewController.modalViewController == self)…
meilleure façon de vérifier
if (self.navigationController.presentingViewController) {
NSLog(@"Model Present");
}
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;
}
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
}
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];
}
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.
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.
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.
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
}