Verifique si el controller de vista se presenta de manera modal o si se presiona en una stack de navigation

¿Cómo puedo, en mi opinión, el código del controller, diferenciar entre:

  • presentado modalmente
  • empujado en la stack de navigation

Both presentingViewController y isMovingToParentViewController son YES en ambos casos, por lo que no son muy útiles.

Lo que complica las cosas es que el controller de vista principal es a veces modal, en el que se presiona el controller de vista que se va a verificar.

Resulta que mi problema es que incruste mi HtmlViewController en un UINavigationController que luego se presenta. Es por eso que mis propios bashs y las buenas respuestas a continuación no funcionaron.

 HtmlViewController* termsViewController = [[HtmlViewController alloc] initWithDictionary:dictionary]; UINavigationController* modalViewController; modalViewController = [[UINavigationController alloc] initWithRootViewController:termsViewController]; modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; [self presentViewController:modalViewController animated:YES completion:nil]; 

Creo que será mejor que le diga a mi controller de vista cuándo es modal, en lugar de tratar de determinar.

Toma con un poco de sal, no lo probaste.

 - (BOOL)isModal { if([self presentingViewController]) return YES; if([[[self navigationController] presentingViewController] presentedViewController] == [self navigationController]) return YES; if([[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]]) return YES; return NO; } 

Has pasado por alto un método: isBeingPresented .

isBeingPresented es verdadero cuando el controller de vista se presenta y es falso al ser empujado.

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if ([self isBeingPresented]) { // being presented } else if ([self isMovingToParentViewController]) { // being pushed } else { // simply showing again because another VC was dismissed } } 

En Swift :

 func isModal() -> Bool { if self.presentingViewController != nil { return true } else if self.navigationController?.presentingViewController?.presentedViewController == self.navigationController { return true } else if self.tabBarController?.presentingViewController is UITabBarController { return true } return false } 

self.navigationController! = nil significaría que está en una stack de navigation.

Para manejar el caso de que el controller de vista actual se presione mientras el controller de navigation se presenta de manera modal, he agregado algunas líneas de código para verificar si el controller de vista actual es el controller raíz en la stack de navigation.

 extension UIViewController{ func isModal() -> Bool { if let navigationController = self.navigationController{ if navigationController.viewControllers.first != self{ return false } } if self.presentingViewController != nil { return true } if self.navigationController?.presentingViewController?.presentedViewController == self.navigationController { return true } if self.tabBarController?.presentingViewController is UITabBarController { return true } return false } } 

self.navigationController != nil significaría que está en una stack de navigation.

Swift 3
Aquí hay una solución que aborda el problema mencionado con las respuestas anteriores, cuando isModal() devuelve true si se presiona UIViewController está en una stack UINavigationController presentada.

 extension UIViewController { var isModal: Bool { if let index = navigationController?.viewControllers.index(of: self), index > 0 { return false } else if presentingViewController != nil { return true } else if navigationController?.presentingViewController?.presentedViewController == navigationController { return true } else if tabBarController?.presentingViewController is UITabBarController { return true } else { return false } } } 

Me funciona hasta ahora. Si algunas optimizaciones, por favor comparta.

Como sugieren muchas personas aquí, los methods de "comprobación" no funcionan bien en todos los casos, en mi proyecto he creado una solución para administrarlos de forma manual. El punto es que, por lo general, administramos la presentación por nuestra count, esto no es lo que sucede detrás de la escena y debemos introspectar.

Archivo DEViewController.h :

 #import <UIKit/UIKit.h> // it is a base class for all view controllers within a project @interface DEViewController : UIViewController // specify a way viewcontroller, is presented by another viewcontroller // the presented view controller should manually assign the value to it typedef NS_ENUM(NSUInteger, SSViewControllerPresentationMethod) { SSViewControllerPresentationMethodUnspecified = 0, SSViewControllerPresentationMethodPush, SSViewControllerPresentationMethodModal, }; @property (nonatomic) SSViewControllerPresentationMethod viewControllerPresentationMethod; // other properties/methods... @end 

Las presentaciones ahora podrían gestionarse de esta manera:

empujado en la stack de navigation:

 // DETestViewController inherits from DEViewController DETestViewController *vc = [DETestViewController new]; vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodPush; [self.navigationController pushViewController:vc animated:YES]; 

presentado de manera modal con navigation:

 DETestViewController *vc = [DETestViewController new]; vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; [self presentViewController:nav animated:YES completion:nil]; 

presentado de manera modal:

 DETestViewController *vc = [DETestViewController new]; vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal; [self presentViewController:vc animated:YES completion:nil]; 

Además, en DEViewController podríamos agregar un respaldo a "comprobar" si la propiedad antes mencionada es igual a SSViewControllerPresentationMethodUnspecified :

 - (BOOL)isViewControllerPushed { if (self.viewControllerPresentationMethod != SSViewControllerPresentationMethodUnspecified) { return (BOOL)(self.viewControllerPresentationMethod == SSViewControllerPresentationMethodPush); } else { // fallback to default determination method return (BOOL)self.navigationController.viewControllers.count > 1; } } 

Suponiendo que todos los viewControllers que presenta de manera modal están envueltos dentro de un nuevo controlController (que siempre debe hacer de todos modos), puede agregar esta propiedad a su VC.

 private var wasPushed: Bool { guard let vc = navigationController?.viewControllers.first where vc == self else { return true } return false } 

Si está utilizando ios 5.0 o posterior, use este código

 -(BOOL)isPresented { if ([self isBeingPresented]) { // being presented return YES; } else if ([self isMovingToParentViewController]) { // being pushed return NO; } else { // simply showing again because another VC was dismissed return NO; } 

}

 id presentedController = self.navigationController.modalViewController; if (presentedController) { // Some view is Presented } else { // Some view is Pushed } 

Esto le permitirá saber si viewController se presenta o se presiona

Para alguien que se pregunta, cómo decirle a ViewController que se está presentando

si A está presentando / empujando B

  1. Definir una enum y property en B

     enum ViewPresentationStyle { case Push case Present } //and write property var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed 
  2. Ahora, en el controller de vista, diga a B si se está presentando / presionando asignando presentationStyle

     func presentBViewController() { let bViewController = B() bViewController.vcPresentationStyle = .Present //telling B that it is being presented self.presentViewController(bViewController, animated: true, completion: nil) } 
  3. Uso en B View Controller

     override func viewDidLoad() { super.viewDidLoad() if self.vcPresentationStyle == .Present { //is being presented } else { //is being pushed } }