Réponses:
Depuis modalViewController
est obsolète dans iOS 6, voici une version qui fonctionne pour iOS 5+ et qui se compile sans avertissement.
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
}
Pointe du chapeau à la réponse de Felipe.
nil == nil
retourne YES
, et ce n'est pas le résultat que l'on veut.
Si vous recherchez iOS 6+, cette réponse est obsolète et vous devriez vérifier la réponse de Gabriele Petronella
Il n'y a pas de moyen efficace de le faire, en tant que propriété ou méthode native d'UIKit. Ce que vous pouvez faire est de vérifier plusieurs aspects de votre contrôleur pour vous assurer qu'il est présenté comme modal.
Donc, pour vérifier si le contrôleur actuel (représenté comme self
dans le code ci-dessous) est présenté de manière modale ou non, j'ai la fonction ci-dessous soit dans une UIViewController
catégorie, 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é la dernière vérification pour voir si un UITabBarController est utilisé, et vous présentez un autre UITabBarController comme modal.
EDIT 2: ajout de la vérification iOS 5+, où UIViewController
ne répond parentViewController
plus, mais à la presentingViewController
place.
EDIT 3: J'ai créé un résumé pour cela au cas où https://gist.github.com/3174081
modalViewController
propriété est obsolète à partir d'iOS 6. La documentation suggère de l'utiliser à la presentedViewController
place.
NSLog(@"%@", self.navigationController.parentViewController)
estampes (null)
- pourriez-vous expliquer pourquoi? Mon ViewController est connecté au contrôleur de vue modale via navController dans le storyboard.
.parentViewController
est obsolète, .presentingViewController
doit être utilisé à la place.
Dans iOS5 +, comme vous pouvez le voir dans UIViewController Class Reference , vous pouvez l'obtenir à partir de la propriété "presentationViewController".
presentantViewController Le contrôleur de vue qui a présenté ce contrôleur de vue. (lecture seulement)
@property (non atomique, en lecture seule) UIViewController * présentant ViewController
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 que l'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.
Disponibilité
Disponible dans iOS 5.0 et versions ultérieures.
Déclaré dans
UIViewController.h
presentingViewController
. Il fonctionnera également dans les contrôleurs de vue de conteneur, car il traverse automatiquement les ancêtres.
Si ce n'est pas le cas, vous pouvez définir une propriété pour this ( 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 viewWillAppear
remplacement.
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 la vôtre.
UINavigationController
comme modal ... sauf si vous créez un contrôleur de navigation personnalisé juste pour ajouter cette propriété. Et après cela, à l'intérieur des contrôleurs, vous devrez continuer à lancer self.navigationController
dans cette classe personnalisée à chaque fois que vous devez vérifier si le contrôleur est présenté comme modal
La réponse de Petronella ne fonctionne pas si self.navigationController est présenté modalement mais que self n'est pas égal à self.navigationController.viewControllers [0], dans ce 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 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
Cela devrait fonctionner.
if(self.parentViewController.modalViewController == self)…
UINavigationController
et les UITabBarController
cas. Cela fonctionne plutôt bien jusqu'à présent
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, ce qui est le cas dans mon projet (je traitais d'un problème qui ne se produit qu'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 l'édition d'un élément existant) par le contrôleur de vue maître. Lorsque l'utilisateur appuie sur [Terminé], le contrôleur de vue détaillée appelle la méthode du contrôleur de vue principale pour notifier qu'il est prêt à être fermé. Le maître doit déterminer comment le détail est présenté 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];
}
Un hack comme celui-ci pourrait fonctionner.
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);
Pour autant que je l'ai testé, cela fonctionne pour iOS7 et iOS8. Je n'ai pas essayé sur iOS6 cependant.
J'ai regardé un peu partout pour trouver la bonne réponse à cette question, et je n'en ai trouvé aucune couvrant tous les scénarios possibles. J'ai écrit ces quelques lignes de code qui semblent faire le travail. Vous pouvez trouver quelques commentaires en ligne pour savoir 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.
Voici ma version modifiée de @ GabrielePetronella isModal
, qui fonctionne avec les contrôleurs de vue contenus en ce sens qu'elle remonte d'abord la hiérarchie parentViewController. Également extrait le code en plusieurs lignes afin que ce soit clair ce qu'il fait.
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
}