ios - tab - passing data between view controllers swift
¿Presentar un controlador modal sin conocer el controlador de vista actual? (5)
Bueno, puedes seguir la cadena.
Comience en [UIApplication sharedApplication].delegate.window.rootViewController
.
En cada controlador de vista, realice la siguiente serie de pruebas.
Si [viewController isKindOfClass:[UINavigationController class]]
, proceda a [(UINavigationController *)viewController topViewController]
.
Si [viewController isKindOfClass:[UITabBarController class]]
, proceda a [(UITabBarController *)viewController selectedViewController]
.
Si [viewController presentedViewController]
, proceda con [viewController presentedViewController]
.
¿Hay alguna manera de presentar un controlador de vista modalmente sin saber cuál es la vista del controlador de vista visible? Básicamente es como mostrar una vista de alerta en cualquier momento.
Me gustaría poder hacer algo como:
MyViewController *myVC = [[MyViewController alloc] init];
[myVC showModally];
Me gustaría poder llamar esto desde cualquier lugar de la aplicación y hacer que aparezca en la parte superior. No quiero preocuparme por el controlador de vista actual.
Planeo usar esto para mostrar un mensaje de inicio de sesión. No quiero usar una vista de alerta, y tampoco quiero tener un código de presentación de inicio de sesión en toda la aplicación.
Tiene alguna idea sobre esto? ¿O tal vez hay una mejor manera de lograr esto? ¿Debería implementar mi propio mecanismo y simplemente colocar una vista en la parte superior de la ventana?
No creo que necesariamente necesite saber qué controlador de vista es visible. Puede acceder a la keyWindow
de la aplicación y agregar la vista del controlador de vista modal a la parte superior de la lista de vistas. Entonces puede hacer que funcione como UIAlertView
.
Archivo de interfaz: MyModalViewController.h
#import <UIKit/UIKit.h>
@interface MyModalViewController : UIViewController
- (void) show;
@end
Archivo de implementación: MyModalViewController.m
#import "MyModalViewController.h"
@implementation MyModalViewController
- (void) show {
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
// Configure the frame of your modal''s view.
[window addSubview: self.view];
}
@end
Puede tener este código implementado en su delegado de aplicación:
AppDelegate.m
-(void)presentViewControllerFromVisibleController:(UIViewController *)toPresent
{
UIViewController *vc = self.window.rootViewController;
[vc presentViewController:toPresent animated:YES];
}
AppDelegate.h
-(void)presentViewControllerFromVisibleViewController:(UIViewController *)toPresent;
De donde sea
#import "AppDelegate.h"
...
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
[delegate presentViewControllerFromVisibleViewController:myViewControllerToPresent];
En tu delegado, rootViewController
el rootViewController
de la window
. Esto siempre estará visible; es el controlador ''padre'' de todo.
Mi solución en Swift (inspirada en la esencia de MartinMoizard)
extension UIViewController {
func presentViewControllerFromVisibleViewController(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) {
if let navigationController = self as? UINavigationController {
navigationController.topViewController?.presentViewControllerFromVisibleViewController(viewControllerToPresent, animated: flag, completion: completion)
} else if let tabBarController = self as? UITabBarController {
tabBarController.selectedViewController?.presentViewControllerFromVisibleViewController(viewControllerToPresent, animated: flag, completion: completion)
} else if let presentedViewController = presentedViewController {
presentedViewController.presentViewControllerFromVisibleViewController(viewControllerToPresent, animated: flag, completion: completion)
} else {
present(viewControllerToPresent, animated: flag, completion: completion)
}
}
}
Esta solución le proporciona el controlador de vista superior para que pueda manejar cualquier condición especial antes de presentar desde allí. Por ejemplo, tal vez desee presentar su controlador de vista solo si el controlador de vista superior no es un controlador de vista específico.
extension UIApplication {
/// The top most view controller
static var topMostViewController: UIViewController? {
return UIApplication.shared.keyWindow?.rootViewController?.visibleViewController
}
}
extension UIViewController {
/// The visible view controller from a given view controller
var visibleViewController: UIViewController? {
if let navigationController = self as? UINavigationController {
return navigationController.topViewController?.visibleViewController
} else if let tabBarController = self as? UITabBarController {
return tabBarController.selectedViewController?.visibleViewController
} else if let presentedViewController = presentedViewController {
return presentedViewController.visibleViewController
} else {
return self
}
}
}
Con esto puede presentar su controlador de vista desde cualquier lugar sin necesidad de saber cuál es el controlador de vista superior
UIApplication.topMostViewController?.present(viewController, animated: true, completion: nil)
O presente su controlador de vista solo si el controlador de vista superior no es un controlador de vista específico
if let topVC = UIApplication.topMostViewController, !(topVC is FullScreenAlertVC) {
topVC.present(viewController, animated: true, completion: nil)
}
Una cosa a tener en cuenta es que si hay un UIAlertController actualmente en exhibición, UIApplication.topMostViewController
devolverá un UIAlertController
. Presentarse sobre un UIAlertController
tiene un comportamiento extraño y debe evitarse. Como tal, debe verificarlo manualmente !(UIApplication.topMostViewController is UIAlertController)
antes de presentar, o agregar un else if
para devolver nil si self is UIAlertController
extension UIViewController {
/// The visible view controller from a given view controller
var visibleViewController: UIViewController? {
if let navigationController = self as? UINavigationController {
return navigationController.topViewController?.visibleViewController
} else if let tabBarController = self as? UITabBarController {
return tabBarController.selectedViewController?.visibleViewController
} else if let presentedViewController = presentedViewController {
return presentedViewController.visibleViewController
} else if self is UIAlertController {
return nil
} else {
return self
}
}
}