Risposte:
Poiché modalViewController
è stato deprecato in iOS 6, ecco una versione che funziona per iOS 5+ e che si compila senza avvisi.
Objective-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
}
Punta di cappello alla risposta di Felipe.
nil == nil
ritorna YES
, e non è il risultato che vogliamo.
Se stai cercando iOS 6+, questa risposta è deprecata e dovresti controllare la risposta di Gabriele Petronella
Non esiste un modo pulito per farlo, come proprietà o metodo nativo di UIKit. Quello che puoi fare è controllare diversi aspetti del tuo controller per assicurarti che sia presentato come modale.
Quindi, per verificare se il controller corrente (rappresentato come self
nel codice sotto) è presentato in modo modale o meno, ho la funzione qui sotto o in una UIViewController
categoria, o (se il tuo progetto non ha bisogno di usare altri controller UIKit, come UITableViewController
ad esempio) in un controller di base ereditato dagli altri miei controller
-(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: ho aggiunto l'ultimo controllo per vedere se viene utilizzato un UITabBarController e presenti un altro UITabBarController come modale.
EDIT 2: aggiunto il controllo iOS 5+, dove UIViewController
non risponde parentViewController
più, ma presentingViewController
invece.
EDIT 3: ho creato un succo per questo nel caso https://gist.github.com/3174081
modalViewController
proprietà è deprecata a partire da iOS 6. La documentazione suggerisce di utilizzare presentedViewController
invece.
NSLog(@"%@", self.navigationController.parentViewController)
stampe (null)
- potresti spiegare perché? Il mio ViewController è connesso al controller di visualizzazione modale tramite navController nello storyboard.
.parentViewController
è deprecato, .presentingViewController
deve essere utilizzato invece.
In iOS5 +, come puoi vedere in UIViewController Class Reference , puoi ottenerlo dalla proprietà "presentationViewController".
presentandoViewController Il controller di visualizzazione che ha presentato questo controller di visualizzazione. (sola lettura)
@property (nonatomic, readonly) UIViewController * presentationViewController
Discussione
Se il controller di visualizzazione che ha ricevuto questo messaggio viene presentato da un altro controller di visualizzazione, questa proprietà contiene il controller di visualizzazione che lo presenta. Se il controller della visualizzazione non viene presentato, ma viene presentato uno dei suoi antenati, questa proprietà detiene il controller della visualizzazione che presenta l'antenato più vicino. Se non vengono presentati né il view controller né alcuno dei suoi antenati, questa proprietà è nulla.
Disponibilità
Disponibile in iOS 5.0 e versioni successive.
Dichiarato in
UIViewController.h
presentingViewController
. Funzionerà anche nei controller di visualizzazione del contenitore, poiché attraversa automaticamente gli antenati.
In caso contrario, è possibile definire una proprietà per this ( presentedAsModal
) nella sottoclasse UIViewController e impostarla su YES
prima di presentare ViewController come vista modale.
childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];
Puoi controllare questo valore nel tuo viewWillAppear
override.
Credo che non ci sia una proprietà ufficiale che dichiari come viene presentata la vista, ma nulla ti impedisce di crearne una tua.
UINavigationController
come modale ... a meno che non si crei un controller di navigazione personalizzato solo per aggiungere questa proprietà. Dopodiché, all'interno dei controller, dovrai continuare a trasmettere self.navigationController
a questa classe personalizzata ogni volta che devi controllare se il controller è presentato come modale
La risposta di Petronella non funziona se self.navigationController è presentato in modo modale ma self non è uguale a self.navigationController.viewControllers [0], in quel caso self viene spinto.
Ecco come potresti risolvere il problema.
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]];
E in 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
Questo dovrebbe funzionare.
if(self.parentViewController.modalViewController == self)…
UINavigationController
e UITabBarController
casi. Sta funzionando abbastanza bene finora
Il modo migliore per controllare
if (self.navigationController.presentingViewController) {
NSLog(@"Model Present");
}
Se non è necessario distinguere tra viste modali a schermo intero e viste non modali, come nel mio progetto (avevo a che fare con un problema che si verifica solo con i fogli modulo e i fogli di pagina), puoi utilizzare modalPresentationStyle proprietà di 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
}
Nel mio progetto ho un controller di visualizzazione (Dettaglio) che può essere presentato in modo modale (quando si aggiunge un nuovo elemento) o con push (quando si modifica uno esistente) dal controller di visualizzazione Master. Quando l'utente tocca [Fine], il controller della vista dettagliata chiama il metodo del controller della vista principale per notificare che è pronto per essere chiuso. Il Maestro deve determinare come viene presentato il dettaglio per sapere come chiuderlo. Ecco come lo faccio:
UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
[self dismissViewControllerAnimated:YES completion:NULL];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
Un trucco come questo potrebbe funzionare.
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
}
Tuttavia, penso che la mia risposta precedente sia una soluzione più pulita.
Quello che ha funzionato per me è seguire:
// 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);
Per quanto l'ho testato, funziona per iOS7 e iOS8. Tuttavia, non ho provato su iOS6.
Ho guardato un po 'in giro per trovare la risposta giusta a questa domanda e non sono riuscito a trovare nessuna che coprisse tutti i possibili scenari. Ho scritto queste poche righe di codice che sembrano fare il lavoro. Puoi trovare alcuni commenti in linea per capire cosa è stato controllato.
- (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;
}
Spero che questo aiuto.
Ecco la mia versione modificata di @ GabrielePetronella's isModal
, che funziona con i controller di visualizzazione contenuti in quanto sale prima nella gerarchia di parentViewController. Inoltre ha estratto il codice in più righe in modo che sia chiaro cosa sta facendo.
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
}