Get top most UIViewController

2019-01-01 12:20发布

I can't seem to get the top most UIViewController without access to a UINavigationController. Here is what I have so far:

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(vc, animated: true, completion: nil)

However, it does not seem to do anything. The keyWindow and rootViewController seem to be non-nil values too, so the optional chaining shouldn't be an issue.

NOTE: It is a bad idea to do something like this. It breaks the MVC pattern.

13条回答
与风俱净
2楼-- · 2019-01-01 12:58

I loved @dianz's answer, and so here is the swift 3's version of it. It's basically the same thing but his was missing a curly brace and some of the syntax/variable/method names have changed. So here it is!

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
    }
}

Usage is still the exact same though:

if let topController = UIApplication.topViewController() {
    print("The view controller you're looking at is: \(topController)")
}
查看更多
梦寄多情
3楼-- · 2019-01-01 13:01

https://gist.github.com/db0company/369bfa43cb84b145dfd8 I did some tests on the answers and comments on this site. For me, the following works

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()
    }
}

Then, get the top viewController by:

UIApplication.shared.topMostViewController()
查看更多
余生请多指教
4楼-- · 2019-01-01 13:01

To find the visible viewController in Swift 3

if let viewControllers = window?.rootViewController?.childViewControllers {

     let prefs = UserDefaults.standard

     if viewControllers[viewControllers.count - 1] is ABCController{
        print("[ABCController] is visible")

     }
}

This code find the last added or the last active controller visible.

This I have used in AppDelegate to find active view Controller

查看更多
临风纵饮
5楼-- · 2019-01-01 13:02

you can define a UIViewController variable in AppDelegate, and in every viewWillAppear set the variable to self.(however dianz answer is the best answer.)

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
    appDel.currentVC = self
}
查看更多
临风纵饮
6楼-- · 2019-01-01 13:04

have this 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
    }
}

You can you use this anywhere on your controller

if let topController = UIApplication.topViewController() {

}
查看更多
公子世无双
7楼-- · 2019-01-01 13:06

Based on Dianz answer, the Objective-C version

- (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;
}
查看更多
登录 后发表回答