Respuestas:
Dado que modalViewController
ha quedado obsoleto en iOS 6, aquí hay una versión que funciona para iOS 5+ y que se compila sin advertencias.
C objetivo:
- (BOOL)isModal {
return self.presentingViewController.presentedViewController == self
|| (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
|| [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}
Rápido:
var isModal: Bool {
return self.presentingViewController?.presentedViewController == self
|| (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController)
|| self.tabBarController?.presentingViewController is UITabBarController
}
Punta de sombrero a la respuesta de Felipe.
nil == nil
devuelve YES
, y no es el resultado que queremos.
Si está buscando iOS 6+, esta respuesta está obsoleta y debe verificar la respuesta de Gabriele Petronella
No hay una forma sencilla de hacerlo, como propiedad o método nativo de UIKit. Lo que puede hacer es verificar varios aspectos de su controlador para asegurarse de que se presente como modal.
Entonces, para verificar si el controlador actual (representado como self
en el código a continuación) se presenta de una manera modal o no, tengo la función a continuación en una UIViewController
categoría o (si su proyecto no necesita usar otros controladores UIKit, como UITableViewController
por ejemplo) en un controlador base que heredan mis otros controladores
-(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;
}
EDITAR: agregué la última verificación para ver si se está utilizando un UITabBarController, y presenta otro UITabBarController como modal.
EDIT 2: se agregó la verificación de iOS 5+, donde UIViewController
ya no responde parentViewController
, sino a presentingViewController
.
EDITAR 3: He creado una esencia para ello por si acaso https://gist.github.com/3174081
modalViewController
propiedad está obsoleta a partir de iOS 6. La documentación sugiere utilizarla presentedViewController
en su lugar.
NSLog(@"%@", self.navigationController.parentViewController)
impresiones (null)
- ¿podría explicar por qué? My ViewController está conectado con el controlador de vista modal a través de navController en el guión gráfico.
.parentViewController
está en desuso, .presentingViewController
debe usarse en su lugar.
En iOS5 +, como puede ver en UIViewController Class Reference , puede obtenerlo de la propiedad "presentationViewController".
presentViewController El controlador de vista que presentó este controlador de vista. (solo lectura)
@property (no atómico, solo lectura) UIViewController * PresentandoViewController
Discusión
Si el controlador de vista que recibió este mensaje es presentado por otro controlador de vista, esta propiedad contiene el controlador de vista que lo presenta. Si no se presenta el controlador de vista, pero se presenta uno de sus antepasados, esta propiedad contiene el controlador de vista que presenta el antepasado más cercano. Si no se presentan ni el controlador de vista ni ninguno de sus antepasados, esta propiedad es nula.
Disponibilidad
Disponible en iOS 5.0 y posterior.
Declarado en
UIViewController.h
presentingViewController
. También funcionará en controladores de vista de contenedor, ya que atraviesa automáticamente los antepasados.
Si no lo hay, puede definir una propiedad para esto (presentedAsModal
) en su subclase UIViewController y establecerla en YES
antes de presentar ViewController como una vista modal.
childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];
Puede comprobar este valor en su viewWillAppear
anulación.
Creo que no hay una propiedad oficial que indique cómo se presenta la vista, pero nada le impide crear la suya propia.
UINavigationController
como modal ... a menos que cree un controlador de navegación personalizado solo para agregar esta propiedad. Y después de eso, dentro de los controladores, tendrás que seguir transmitiendo self.navigationController
a esta clase personalizada cada vez que necesites verificar si el controlador se presenta como modal
La respuesta de Petronella no funciona si self.navigationController se presenta de forma modal pero self no es igual a self.navigationController.viewControllers [0], en ese caso se empuja self.
Así es como puede solucionar el 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]];
Y en 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
Esto debería funcionar.
if(self.parentViewController.modalViewController == self)…
UINavigationController
y UITabBarController
casos. Está funcionando bastante bien hasta ahora
La mejor forma de comprobar
if (self.navigationController.presentingViewController) {
NSLog(@"Model Present");
}
Si no necesita distinguir entre vistas modales de pantalla completa y vistas no modales, que es el caso en mi proyecto (estaba lidiando con un problema que solo ocurre con hojas de formulario y hojas de página), puede usar modalPresentationStyle propiedad 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;
}
En 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
}
En mi proyecto tengo un controlador de vista (Detalle) que se puede presentar de forma modal (al agregar un nuevo elemento) o con push (al editar uno existente) mediante el controlador de vista maestro. Cuando el usuario toca [Listo], el controlador de vista de detalles llama al método del controlador de vista maestro para notificar que está listo para cerrarse. El maestro tiene que determinar cómo se presenta Detail para saber cómo cerrarlo. Así es como hago esto:
UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
[self dismissViewControllerAnimated:YES completion:NULL];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
Un truco como este podría funcionar.
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
}
Sin embargo, creo que mi respuesta anterior es una solución más limpia.
Lo que funcionó para mí es lo siguiente:
// 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);
Por lo que lo probé, esto funciona para iOS7 e iOS8. Sin embargo, no probé en iOS6.
Miré un poco a mi alrededor para encontrar la respuesta correcta a esta pregunta y no pude encontrar ninguna que cubriera todos los escenarios posibles. Escribí estas pocas líneas de código que parecen hacer el trabajo. Puede encontrar algunos comentarios en línea para averiguar qué se ha verificado.
- (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;
}
Espero que esto ayude.
Aquí está mi versión modificada de @ GabrielePetronella isModal
, que funciona con controladores de vista contenidos, ya que primero sube por la jerarquía parentViewController. También extrajo el código en varias líneas para que quede claro lo que está haciendo.
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
}