Est-il possible de déterminer si ViewController est présenté comme modal?
Est-il possible de vérifier à l'intérieur de la classe ViewController qu'elle est présentée comme contrôleur de vue modal?
Puisque modalViewController
est obsolète dans iOS 6, voici une version qui fonctionne pour iOS 5+ et qui est compilée 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]];
}
Rapide:
var isModal: Bool {
return self.presentingViewController?.presentedViewController == self
|| (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController)
|| self.tabBarController?.presentingViewController is UITabBarController
}
Chapeau à la réponse de Felipe.
Si vous cherchez iOS 6+, cette réponse est obsolète et vous devriez vérifier réponse de Gabriele Petronella
Il n’existe aucun moyen astucieux de le faire, en tant que propriété ou 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 modal.
Donc, pour vérifier si le contrôleur actuel (représenté par self
dans le code ci-dessous) est présenté de manière modale ou non, I avoir la fonction ci-dessous soit dans une catégorie UIViewController
, soit (si votre projet n'a pas besoin d'utiliser d'autres contrôleurs UIKit, comme UITableViewController
par exemple) dans un contrôleur de base dont mes autres contrôleurs héritent
-(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é le dernier contrôle pour voir si un UITabBarController est utilisé, et vous présentez un autre UITabBarController comme modal.
EDIT 2: ajout du contrôle iOS 5+, où UIViewController
ne répond plus pour parentViewController
, mais à presentingViewController
à la place.
EDIT 3: J'ai créé un Gist pour cela au cas où https://Gist.github.com/3174081
Comme dans iOS5 +, comme vous pouvez le voir dans référence de la classe UIViewController , vous pouvez l'obtenir à partir de la propriété "PresentationViewController".
presentationViewController Le contrôleur de vue qui a présenté ce contrôleur de vue. (lecture seulement)
@property (nonatomic, en lecture seule) UIViewController * PresentationViewController
Discussion
Si le contrôleur de vue ayant reçu ce message est présenté par un autre contrôleur de vue, cette propriété conserve le contrôleur de vue qui le présente. Si le contrôleur de vue n'est pas présenté, mais que l'un de ses ancêtres l'est, cette propriété conserve 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é a la valeur nil.
Disponibilité
Disponible dans iOS 5.0 et versions ultérieures.
Déclaré dans
UIViewController.h
Si ce n'est pas le cas, vous pouvez définir une propriété pour cela (presentedAsModal
) dans votre sous-classe UIViewController et la définir sur YES
avant de présenter ViewController en tant que vue modale.
childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];
Vous pouvez vérifier cette valeur dans votre substitution viewWillAppear
.
Je crois qu’aucune propriété officielle n’indique comment la vue est présentée, mais rien ne vous empêche de créer la vôtre.
réponse de Petronella ne fonctionne pas si self.navigationController est présenté de manière modale mais self n'est pas égal à self.navigationController.viewControllers [0], auquel cas self 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 à 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
Cela devrait marcher.
if(self.parentViewController.modalViewController == self)…
Meilleur moyen 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, comme c'est le cas dans mon projet (je traitais d'un problème qui se produit uniquement avec les feuilles de formulaire et les feuilles de page), vous pouvez utiliser le modalPresentationStyle. propriété 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;
}
Dans 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 (Détail) qui peut être présenté de manière modale (lors de l'ajout d'un nouvel élément) ou avec Push (lors de la modification d'un article existant) par le contrôleur de vue principal. Lorsque l'utilisateur appuie sur [Terminé], le contrôleur de la vue détaillée appelle la méthode du contrôleur de la vue principale pour notifier qu'il est prêt à être fermé. Le maître doit déterminer comment les détails sont présentés afin de savoir comment le fermer. Voici comment je fais ceci:
UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
[self dismissViewControllerAnimated:YES completion:NULL];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
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);
Pour autant que je l'ai testé, cela fonctionne pour iOS7 et iOS8. Je n'ai pas essayé sur iOS6 cependant.
Voici ma version modifiée de @ GabrielePetronella isModal
, qui fonctionne avec les contrôleurs de vue contenus dans le sens où elle affiche d'abord la hiérarchie parentViewController. Tirez également le code sur 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
}
J'ai un peu cherché autour de moi pour trouver la bonne réponse à cette question et je n'en ai trouvé aucun qui couvre tous les scénarios possibles. J'ai écrit ces quelques lignes de code qui semblent faire l'affaire. Vous pouvez trouver quelques 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;
}
J'espère que cette aide.
Un hack comme ça 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.