Je n'arrive pas à obtenir le plus haut UIViewController
sans accès à un 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. keyWindow
et rootViewController
semblent également être des valeurs non nulles, de sorte que l'enchaînement facultatif ne devrait pas poser de problème.
NOTE: C'est une mauvaise idée de faire quelque chose comme ça. Cela casse le modèle MVC.
presentViewController
montre un contrôleur de vue. Il ne retourne pas un contrôleur de vue. Si vous n'utilisez pas une UINavigationController
, vous cherchez probablement presentedViewController
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
}
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 vous en servir n'importe où sur votre contrôleur
if let topController = UIApplication.topViewController() {
}
Pour que Swift 4.2 trouve la meilleure vue possible
extension UIApplication {
class func getTopMostViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return getTopMostViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return getTopMostViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return getTopMostViewController(base: presented)
}
return base
}
}
Comment utiliser
if let topVC = UIApplication.getTopMostViewController() {
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
}
}
}
}
Usage:
if let topController = window.visibleViewController() {
println(topController)
}
Basé sur Dianz answer, 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;
}
https://Gist.github.com/db0company/369bfa43cb84b145dfd8 J'ai fait quelques tests sur les réponses et les 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 le top viewController par:
UIApplication.shared.topMostViewController()
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 noms de syntaxe/variable/méthode ont changé. Alors voila!
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 si:
if let topController = UIApplication.topViewController() {
print("The view controller you're looking at is: \(topController)")
}
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;
}
}
}
}
Utilisez ce code pour trouver le meilleur UIViewController
func getTopViewController() -> UIViewController? {
var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
while topController?.presentedViewController != nil {
topController = topController?.presentedViewController
}
return topController
}
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
}
Pour trouver la vue visible Contrôleur 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é ajouté ou le dernier contrôleur actif visible.
J'ai utilisé cela dans AppDelegate pour trouver le contrôleur de vue actif
vous pouvez définir une variable UIViewController dans AppDelegate et dans chaque viewWillAppear, définissez la variable sur self (toutefois, dianz answer est la meilleure réponse).
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
appDel.currentVC = self
}
Trop de saveurs, mais aucune n’est une itérative élaborée. 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
}
Dans de très rares cas, avec la séquence personnalisée, le contrôleur de vue le plus en haut ne se trouve pas dans un contrôleur de pile de navigation ni dans la barre de tabulation, ni dans la présentation, mais sa vue est insérée en haut des vues secondaires de la clé.
Dans ce cas, il est nécessaire de vérifier si UIApplication.shared.keyWindow.subviews.last == self.view
permet de déterminer si le contrôleur de vue actuel est le plus performant.
Où avez-vous mis le code?
J'ai essayé votre code dans ma démo, j'ai découvert, si vous mettez le code dans
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
échouera, car la fenêtre de clé a été mise encore.
Mais je mets votre code dans certains contrôleur de vue
override func viewDidLoad() {
Ça fonctionne.
La meilleure solution pour moi est une extension avec une fonction. Créez un fichier Swift avec cette extension
Premièrement, 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 ce fichier, ajouter une fonction
func visibleViewController() -> UIViewController? {
let appDelegate = UIApplication.shared.delegate
if let window = appDelegate!.window {
return window?.visibleViewController
}
return nil
}
Et si vous voulez 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 du fichier est comme ça:
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
}
var topViewController: UIViewController? {
guard var topViewController = UIApplication.shared.keyWindow?.rootViewController else { return nil }
while let presentedViewController = topViewController.presentedViewController {
topViewController = presentedViewController
}
return topViewController
}