swift - containerview - Obtenga la mayoría de UIViewController
view controller que es (17)
Parece que no puedo obtener la mayor cantidad de
UIViewController
sin acceso a un
UINavigationController
.
Esto es lo que tengo hasta ahora:
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(vc, animated: true, completion: nil)
Sin embargo, no parece hacer nada.
keyWindow
y
rootViewController
parecen ser valores no nulos, por lo que el encadenamiento opcional no debería ser un problema.
NOTA: es una mala idea hacer algo como esto. Rompe el patrón MVC.
¿Dónde pusiste el código?
Probé tu código en mi demo, descubrí, si pones el código en
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
fallará, porque la ventana clave se ha configurado todavía.
Pero puse tu código en algún controlador de vista
override func viewDidLoad() {
Simplemente funciona
Basado en Bob -c arriba:
Swift 3.0
extension UIWindow {
func visibleViewController() -> UIViewController? {
if let rootViewController: UIViewController = self.rootViewController {
return UIWindow.getVisibleViewControllerFrom(vc: rootViewController)
}
return nil
}
class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
if vc.isKind(of: UINavigationController.self) {
let navigationController = vc as! UINavigationController
return UIWindow.getVisibleViewControllerFrom( vc: navigationController.visibleViewController!)
} else if vc.isKind(of: UITabBarController.self) {
let tabBarController = vc as! UITabBarController
return UIWindow.getVisibleViewControllerFrom(vc: tabBarController.selectedViewController!)
} else {
if let presentedViewController = vc.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(vc: presentedViewController)
} else {
return vc;
}
}
}
}
Basado en la respuesta de Dianz, la versión Objective-C
- (UIViewController *) topViewController {
UIViewController *baseVC = UIApplication.sharedApplication.keyWindow.rootViewController;
if ([baseVC isKindOfClass:[UINavigationController class]]) {
return ((UINavigationController *)baseVC).visibleViewController;
}
if ([baseVC isKindOfClass:[UITabBarController class]]) {
UIViewController *selectedTVC = ((UITabBarController*)baseVC).selectedViewController;
if (selectedTVC) {
return selectedTVC;
}
}
if (baseVC.presentedViewController) {
return baseVC.presentedViewController;
}
return baseVC;
}
Demasiados sabores pero ninguno uno elaborado e iterativo. Combinado de los anteriores:
func topMostController() -> UIViewController? {
var from = UIApplication.shared.keyWindow?.rootViewController
while (from != nil) {
if let to = (from as? UITabBarController)?.selectedViewController {
from = to
} else if let to = (from as? UINavigationController)?.visibleViewController {
from = to
} else if let to = from?.presentedViewController {
from = to
} else {
break
}
}
return from
}
En un caso muy raro, con segue personalizado, el controlador de vista superior no está en una pila de navegación o controlador de barra de pestañas o presentado, pero su vista se inserta en la parte superior de las subvistas de ventanas clave.
En tal situación, es necesario verificar si
UIApplication.shared.keyWindow.subviews.last == self.view
para determinar si el controlador de vista actual es el más alto.
La mejor solución para mí es una extensión con una función. Crea un archivo rápido con esta extensión
Primero es la extensión UIWindow :
public extension UIWindow {
var visibleViewController: UIViewController? {
return UIWindow.visibleVC(vc: self.rootViewController)
}
static func visibleVC(vc: UIViewController?) -> UIViewController? {
if let navigationViewController = vc as? UINavigationController {
return UIWindow.visibleVC(vc: navigationViewController.visibleViewController)
} else if let tabBarVC = vc as? UITabBarController {
return UIWindow.visibleVC(vc: tabBarVC.selectedViewController)
} else {
if let presentedVC = vc?.presentedViewController {
return UIWindow.visibleVC(vc: presentedVC)
} else {
return vc
}
}
}
}
dentro de esa función de agregar archivo
func visibleViewController() -> UIViewController? {
let appDelegate = UIApplication.shared.delegate
if let window = appDelegate!.window {
return window?.visibleViewController
}
return nil
}
Y si desea usarlo, puede llamarlo en cualquier lugar. Ejemplo :
override func viewDidLoad() {
super.viewDidLoad()
if let topVC = visibleViewController() {
//show some label or text field
}
}
El código del archivo es así :
import UIKit
public extension UIWindow {
var visibleViewController: UIViewController? {
return UIWindow.visibleVC(vc: self.rootViewController)
}
static func visibleVC(vc: UIViewController?) -> UIViewController? {
if let navigationViewController = vc as? UINavigationController {
return UIWindow.visibleVC(vc: navigationViewController.visibleViewController)
} else if let tabBarVC = vc as? UITabBarController {
return UIWindow.visibleVC(vc: tabBarVC.selectedViewController)
} else {
if let presentedVC = vc?.presentedViewController {
return UIWindow.visibleVC(vc: presentedVC)
} else {
return vc
}
}
}
}
func visibleViewController() -> UIViewController? {
let appDelegate = UIApplication.shared.delegate
if let window = appDelegate!.window {
return window?.visibleViewController
}
return nil
}
Me encantó la respuesta de @ dianz , así que aquí está la versión rápida de 3. Básicamente es lo mismo, pero le faltaba una llave y algunos de los nombres de sintaxis / variable / método han cambiado. ¡Asi que aqui esta!
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
Sin embargo, el uso sigue siendo exactamente el mismo:
if let topController = UIApplication.topViewController() {
print("The view controller you''re looking at is: /(topController)")
}
Para encontrar la vista visible Controlador en Swift 3
if let viewControllers = window?.rootViewController?.childViewControllers {
let prefs = UserDefaults.standard
if viewControllers[viewControllers.count - 1] is ABCController{
print("[ABCController] is visible")
}
}
Este código encuentra visible el último controlador agregado o el último controlador activo.
Esto lo he usado en AppDelegate para encontrar el controlador de vista activo
Use este código para encontrar los mejores UIViewController
func getTopViewController() -> UIViewController? {
var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
while topController?.presentedViewController != nil {
topController = topController?.presentedViewController
}
return topController
}
Variación leve en @AlberZou usando una variable calculada en lugar de una función
extension UIViewController {
var topMostViewController : UIViewController {
if let presented = self.presentedViewController {
return presented.topMostViewController
}
if let navigation = self as? UINavigationController {
return navigation.visibleViewController?.topMostViewController ?? navigation
}
if let tab = self as? UITabBarController {
return tab.selectedViewController?.topMostViewController ?? tab
}
return self
}
}
extension UIApplication {
var topMostViewController : UIViewController? {
return self.keyWindow?.rootViewController?.topMostViewController
}
}
Luego dice
if let topViewControler = UIApplication.shared.topMostViewController {
... do stuff
}
puede definir una variable UIViewController en AppDelegate y, en cada vista, WillAppear establecer la variable en self (sin embargo, dianz answer es la mejor respuesta).
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
appDel.currentVC = self
}
tener esta extensión
Swift 2. *
extension UIApplication {
class func topViewController(controller: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewController(navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return topViewController(selected)
}
}
if let presented = controller?.presentedViewController {
return topViewController(presented)
}
return controller
}
}
Swift 3
extension UIApplication {
class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewController(controller: navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return topViewController(controller: selected)
}
}
if let presented = controller?.presentedViewController {
return topViewController(controller: presented)
}
return controller
}
}
Puedes usar esto en cualquier lugar de tu controlador
if let topController = UIApplication.topViewController() {
}
https://gist.github.com/db0company/369bfa43cb84b145dfd8 Hice algunas pruebas sobre las respuestas y comentarios en este sitio. Para mí, los siguientes trabajos
extension UIViewController {
func topMostViewController() -> UIViewController {
if let presented = self.presentedViewController {
return presented.topMostViewController()
}
if let navigation = self as? UINavigationController {
return navigation.visibleViewController?.topMostViewController() ?? navigation
}
if let tab = self as? UITabBarController {
return tab.selectedViewController?.topMostViewController() ?? tab
}
return self
}
}
extension UIApplication {
func topMostViewController() -> UIViewController? {
return self.keyWindow?.rootViewController?.topMostViewController()
}
}
Luego, obtenga la vista superior Controlador por:
UIApplication.shared.topMostViewController()
presentViewController
muestra un controlador de vista.
No devuelve un controlador de vista.
Si no está utilizando un
UINavigationController
, probablemente esté buscando
presentedViewController
y deberá comenzar en la raíz e iterar hacia abajo a través de las vistas presentadas.
if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
// topController should now be your topmost view controller
}
Para Swift 3+:
if var topController = UIApplication.shared.keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
// topController should now be your topmost view controller
}
Para un rápido 4/5 + para obtener la vista más alta
// MARK: UIApplication extensions
extension UIApplication {
class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return getTopViewController(base: nav.visibleViewController)
} else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
return getTopViewController(base: selected)
} else if let presented = base?.presentedViewController {
return getTopViewController(base: presented)
}
return base
}
}
Cómo utilizar
if let topVC = UIApplication.getTopViewController() {
topVC.view.addSubview(forgotPwdView)
}
extension UIWindow {
func visibleViewController() -> UIViewController? {
if let rootViewController: UIViewController = self.rootViewController {
return UIWindow.getVisibleViewControllerFrom(vc: rootViewController)
}
return nil
}
static func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
if let navigationController = vc as? UINavigationController,
let visibleController = navigationController.visibleViewController {
return UIWindow.getVisibleViewControllerFrom( vc: visibleController )
} else if let tabBarController = vc as? UITabBarController,
let selectedTabController = tabBarController.selectedViewController {
return UIWindow.getVisibleViewControllerFrom(vc: selectedTabController )
} else {
if let presentedViewController = vc.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(vc: presentedViewController)
} else {
return vc
}
}
}
}
Uso:
if let topController = window.visibleViewController() {
println(topController)
}
var topViewController: UIViewController? {
guard var topViewController = UIApplication.shared.keyWindow?.rootViewController else { return nil }
while let presentedViewController = topViewController.presentedViewController {
topViewController = presentedViewController
}
return topViewController
}