Get top most UIViewController

后端 未结 24 1893
别那么骄傲
别那么骄傲 2020-11-22 14:47

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

UIApplic         


        
相关标签:
24条回答
  • 2020-11-22 15:30

    Too many flavours but none an iterative elaborated one. Combined from the previous ones:

         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
        }
    
    0 讨论(0)
  • 2020-11-22 15:31

    For swift 4 / 5 + to get topmost viewController

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

    How to use

    if let topVC = UIApplication.getTopViewController() {
       topVC.view.addSubview(forgotPwdView)
    }
    
    0 讨论(0)
  • 2020-11-22 15:31

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 15:31

    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()
    
    0 讨论(0)
  • 2020-11-22 15:33

    Where did you put the code in?

    I try your code in my demo, I found out, if you put the code in

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 
    

    will fail, because key window have been setting yet.

    But I put your code in some view controller's

    override func viewDidLoad() {
    

    It just works.

    0 讨论(0)
  • 2020-11-22 15:33

    For anyone looking for a swift 5/iOS 13+ solution (keywindow is deprecated since 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
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题