Je n'arrive pas à tirer le meilleur parti UIViewController
sans accès à un fichier UINavigationController
. Voici ce que j'ai jusqu'à présent:
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(vc, animated: true, completion: nil)
Cependant, cela ne semble rien faire. Les keyWindow
et rootViewController
semblent être des valeurs non nulles également, donc le chaînage facultatif ne devrait pas être un problème.
REMARQUE: faire quelque chose comme ça est une mauvaise idée Il brise le modèle MVC.
Réponses:
presentViewController
montre un contrôleur de vue. Il ne renvoie pas de contrôleur de vue. Si vous n'utilisez pas aUINavigationController
, vous recherchez probablementpresentedViewController
et vous devrez commencer à la racine et parcourir les vues présentées.if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController } // topController should now be your topmost view controller }
Pour Swift 3+:
if var topController = UIApplication.shared.keyWindow?.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController } // topController should now be your topmost view controller }
Pour iOS 13+
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first if var topController = keyWindow?.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController } // topController should now be your topmost view controller }
la source
topController.presentedViewController
renvoie quelque chose (c'est-à-dire que le contrôleur a un contrôleur enfant présenté). C'estwhile let
pour faire respecter le fait qu'iltopController.presentedViewController
faut retourner quelque chose. S'il renvoie nil (c'est-à-dire que le contrôleur n'a aucun enfant présenté), alors il arrêtera la boucle. Dans le corps de la boucle, il réaffecte l'enfant en tant que couranttopController
, et effectue à nouveau une boucle en descendant la hiérarchie du contrôleur de vue. Il peut être réaffectétopController
comme c'est unvar
dans l'if
instruction externe .while let
. Il y a, bien sûr, beaucoup d'if let
exemples à trouver.let x = somethingThatCouldBeNil
syntaxe est une astuce très pratique à utiliser partout où une valeur / condition de vérité pourrait être utilisée. Si nous ne l'utilisions pas ici, nous devrons attribuer explicitement une valeur, puis tester pour voir si elle est réellement là. Je pense que c'est vraiment succinct et expressif.avoir cette extension
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 } }
Vous pouvez l'utiliser n'importe où sur votre manette
if let topController = UIApplication.topViewController() { }
la source
return
). Comment peut-il entrer dans une boucle infinie?Pour swift 4/5 + pour obtenir une vue optimale
// 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 } }
Comment utiliser
if let topVC = UIApplication.getTopViewController() { topVC.view.addSubview(forgotPwdView) }
la source
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 } } } }
Usage:
if let topController = window.visibleViewController() { println(topController) }
la source
return UIWindow.getVisibleViewControllerFrom(presentedViewController.presentedViewController!)
.presentedViewController.presentedViewController
, ou pas?Basé sur la réponse de Dianz, la version 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; }
la source
J'ai adoré la réponse de @ dianz , et voici donc la version de Swift 3. C'est fondamentalement la même chose mais il lui manquait une accolade et certains des noms de syntaxe / variable / méthode ont changé. Alors voilà!
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 } }
L'utilisation est toujours la même:
if let topController = UIApplication.topViewController() { print("The view controller you're looking at is: \(topController)") }
la source
https://gist.github.com/db0company/369bfa43cb84b145dfd8 J'ai fait quelques tests sur les réponses et commentaires sur ce site. Pour moi, les travaux suivants
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() } }
Ensuite, obtenez la vue de dessusController en:
UIApplication.shared.topMostViewController()
la source
Utilisez ce code pour trouver les meilleurs UIViewController
func getTopViewController() -> UIViewController? { var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController while topController?.presentedViewController != nil { topController = topController?.presentedViewController } return topController }
la source
Légère variation sur @AlberZou en utilisant une variable calculée plutôt qu'une fonction
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 } }
Alors dire
if let topViewControler = UIApplication.shared.topMostViewController { ... do stuff }
la source
Basé sur Bob -c ci-dessus:
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; } } } }
la source
Trop de saveurs mais aucune une élaborée itérative. Combiné des précédents:
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 }
la source
import UIKit extension UIApplication { // MARK: Choose keyWindow as per your choice var currentWindow: UIWindow? { connectedScenes .filter({$0.activationState == .foregroundActive}) .map({$0 as? UIWindowScene}) .compactMap({$0}) .first?.windows .filter({$0.isKeyWindow}).first } // MARK: Choose keyWindow as per your choice var keyWindow: UIWindow? { UIApplication.shared.windows.first { $0.isKeyWindow } } class func topMostViewController(base: UIViewController? = UIApplication.shared.currentWindow?.rootViewController) -> UIViewController? { if let nav = base as? UINavigationController { return topMostViewController(base: nav.visibleViewController) } if let tab = base as? UITabBarController { let moreNavigationController = tab.moreNavigationController if let top = moreNavigationController.topViewController, top.view.window != nil { return topMostViewController(base: top) } else if let selected = tab.selectedViewController { return topMostViewController(base: selected) } } if let presented = base?.presentedViewController { return topMostViewController(base: presented) } return base } }
la source
vous pouvez définir une variable UIViewController dans AppDelegate, et dans chaque vueWillAppear définira la variable sur self (cependant, la réponse dianz est la meilleure réponse).
override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) let appDel = UIApplication.sharedApplication().delegate as! AppDelegate appDel.currentVC = self }
la source
Pour trouver le viewController visible dans Swift 3
if let viewControllers = window?.rootViewController?.childViewControllers { let prefs = UserDefaults.standard if viewControllers[viewControllers.count - 1] is ABCController{ print("[ABCController] is visible") } }
Ce code trouve le dernier contrôleur ajouté ou le dernier contrôleur actif visible.
Ceci que j'ai utilisé dans AppDelegate pour trouver le contrôleur de vue active
la source
Pour Swift 5+ , iOS 13+
extension UIViewController { static func topMostViewController() -> UIViewController? { if #available(iOS 13.0, *) { let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first return keyWindow?.rootViewController?.topMostViewController() } return UIApplication.shared.keyWindow?.rootViewController?.topMostViewController() } func topMostViewController() -> UIViewController? { if let navigationController = self as? UINavigationController { return navigationController.topViewController?.topMostViewController() } else if let tabBarController = self as? UITabBarController { if let selectedViewController = tabBarController.selectedViewController { return selectedViewController.topMostViewController() } return tabBarController.topMostViewController() } else if let presentedViewController = self.presentedViewController { return presentedViewController.topMostViewController() } else { return self } } }
Usage:
Lorsque vous obtenez topMostViewController sans instance de UIViewController
guard let viewController = UIViewController.topMostViewController() else { return } print(viewController)
Lorsque vous obtenez topMostViewController de l'instance de UIViewController
let yourVC = UIViewController() guard let vc = yourVC.topMostViewController() else { return } print(vc)
la source
Où avez-vous mis le code?
J'ai essayé votre code dans ma démo, j'ai découvert, si vous mettez le code
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
échouera, car la fenêtre de clé a encore été définie.
Mais j'ai mis votre code dans un contrôleur de vue
override func viewDidLoad() {
Cela fonctionne juste.
la source
didFinishLaunchingWithOptions
. J'en ai juste besoin pour diverses raisons de débogage.Dans un cas très rare, avec un segue personnalisé, le contrôleur de vue le plus haut n'est pas dans une pile de navigation ou un contrôleur de barre d'onglets ou présenté, mais sa vue est insérée en haut des sous-vues de la fenêtre principale.
Dans une telle situation, il est nécessaire de vérifier
UIApplication.shared.keyWindow.subviews.last == self.view
si le contrôleur de vue actuel est le plus haut.la source
Pour tous ceux qui recherchent une solution swift 5 / iOS 13+ (
keywindow
obsolète depuis iOS 13)extension UIApplication { class func getTopMostViewController() -> UIViewController? { let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first if var topController = keyWindow?.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController } return topController } else { return nil } } }
la source
UIApplication.getTopMostViewController()
à l'intérieur de votre ViewController. @ChrisComasiOS13 + // top Contrôleur de vue la plus élevée
extension UIViewController { func topMostViewController() -> UIViewController { if self.presentedViewController == nil { return self } if let navigation = self.presentedViewController as? UINavigationController { return navigation.visibleViewController!.topMostViewController() } if let tab = self.presentedViewController as? UITabBarController { if let selectedTab = tab.selectedViewController { return selectedTab.topMostViewController() } return tab.topMostViewController() } return self.presentedViewController!.topMostViewController() } } extension UIApplication { func topMostViewController() -> UIViewController? { return UIWindow.key!.rootViewController?.topMostViewController() } } extension UIWindow { static var key: UIWindow? { if #available(iOS 13, *) { return UIApplication.shared.windows.first { $0.isKeyWindow } } else { return UIApplication.shared.keyWindow } } } //use let vc = UIApplication.shared.topMostViewController() // End top Most view Controller
la source
var topViewController: UIViewController? { guard var topViewController = UIApplication.shared.keyWindow?.rootViewController else { return nil } while let presentedViewController = topViewController.presentedViewController { topViewController = presentedViewController } return topViewController }
la source
La meilleure solution pour moi est une extension avec une fonction. Créez un fichier rapide avec cette extension
Le premier est l'extension 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 } } } }
à l'intérieur de cette fonction d'ajout de fichier
func visibleViewController() -> UIViewController? { let appDelegate = UIApplication.shared.delegate if let window = appDelegate!.window { return window?.visibleViewController } return nil }
Et si vous souhaitez l'utiliser, vous pouvez l'appeler n'importe où. Exemple :
override func viewDidLoad() { super.viewDidLoad() if let topVC = visibleViewController() { //show some label or text field } }
Le code de fichier est comme ceci :
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 }
la source
extension UIViewController { func topMostViewController() -> UIViewController { if self.presentedViewController == nil { return self } if let navigation = self.presentedViewController as? UINavigationController { return navigation.visibleViewController.topMostViewController() } if let tab = self.presentedViewController as? UITabBarController { if let selectedTab = tab.selectedViewController { return selectedTab.topMostViewController() } return tab.topMostViewController() } return self.presentedViewController!.topMostViewController() } } extension UIApplication { func topMostViewController() -> UIViewController? { return self.keyWindow?.rootViewController?.topMostViewController() } }
la source
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 }
la source
dans SWIFT 5.2
vous pouvez utiliser sous le code:
import UIKit extension UIWindow { static func getTopViewController() -> UIViewController? { if #available(iOS 13, *){ let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first if var topController = keyWindow?.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController } return topController } } else { if var topController = UIApplication.shared.keyWindow?.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController } return topController } } return nil } }
la source