How to find topmost view controller on iOS

后端 未结 30 2307
遥遥无期
遥遥无期 2020-11-22 08:40

I\'ve run into a couple of cases now where it would be convenient to be able to find the \"topmost\" view controller (the one responsible for the current view), but haven\'t

相关标签:
30条回答
  • 2020-11-22 09:08

    I know its very late and might be redundant. But following is the snippet I came up with which is working for me :

        static func topViewController() -> UIViewController? {
            return topViewController(vc: UIApplication.shared.keyWindow?.rootViewController)
        }
    
        private static func topViewController(vc:UIViewController?) -> UIViewController? {
            if let rootVC = vc {
                guard let presentedVC = rootVC.presentedViewController else {
                    return rootVC
                }
                if let presentedNavVC = presentedVC as? UINavigationController {
                    let lastVC = presentedNavVC.viewControllers.last
                    return topViewController(vc: lastVC)
                }
                return topViewController(vc: presentedVC)
            }
            return nil
        }
    
    0 讨论(0)
  • 2020-11-22 09:08

    Another solution relies on the responder chain, which may or may not work depending on what the first responder is:

    1. Get the first responder.
    2. Get the UIViewController associated with that first responder.

    Example pseudo code:

    + (UIViewController *)currentViewController {
        UIView *firstResponder = [self firstResponder]; // from the first link above, but not guaranteed to return a UIView, so this should be handled more appropriately.
        UIViewController *viewController = [firstResponder viewController]; // from the second link above
        return viewController;
    }
    
    0 讨论(0)
  • 2020-11-22 09:12
    - (UIViewController*)topViewController {
        return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
    }
    
    - (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
        if ([rootViewController isKindOfClass:[UITabBarController class]]) {
            UITabBarController* tabBarController = (UITabBarController*)rootViewController;
            return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
        } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
            UINavigationController* navigationController = (UINavigationController*)rootViewController;
            return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
        } else if (rootViewController.presentedViewController) {
            UIViewController* presentedViewController = rootViewController.presentedViewController;
            return [self topViewControllerWithRootViewController:presentedViewController];
        } else {
            return rootViewController;
        }
    }
    
    0 讨论(0)
  • 2020-11-22 09:14

    For latest Swift Version:
    Create a file, name it UIWindowExtension.swift and paste the following snippet:

    import UIKit
    
    public extension UIWindow {
        public var visibleViewController: UIViewController? {
            return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
        }
    
        public static func getVisibleViewControllerFrom(vc: UIViewController?) -> UIViewController? {
            if let nc = vc as? UINavigationController {
                return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
            } else if let tc = vc as? UITabBarController {
                return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
            } else {
                if let pvc = vc?.presentedViewController {
                    return UIWindow.getVisibleViewControllerFrom(pvc)
                } else {
                    return vc
                }
            }
        }
    }
    
    func getTopViewController() -> UIViewController? {
        let appDelegate = UIApplication.sharedApplication().delegate
        if let window = appDelegate!.window {
            return window?.visibleViewController
        }
        return nil
    }
    

    Use it anywhere as:

    if let topVC = getTopViewController() {
    
    }
    
    0 讨论(0)
  • 2020-11-22 09:14
    @implementation UIWindow (Extensions)
    
    - (UIViewController*) topMostController
    {
        UIViewController *topController = [self rootViewController];
    
        while (topController.presentedViewController) {
            topController = topController.presentedViewController;
        }
    
        return topController;
    }
    
    @end
    
    0 讨论(0)
  • 2020-11-22 09:14

    Simple extension for UIApplication in Swift:

    NOTE:

    It cares about moreNavigationController within UITabBarController

    extension UIApplication {
    
        class func topViewController(baseViewController: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {
    
            if let navigationController = baseViewController as? UINavigationController {
                return topViewController(navigationController.visibleViewController)
            }
    
            if let tabBarViewController = baseViewController as? UITabBarController {
    
                let moreNavigationController = tabBarViewController.moreNavigationController
    
                if let topViewController = moreNavigationController.topViewController where topViewController.view.window != nil {
                    return topViewController(topViewController)
                } else if let selectedViewController = tabBarViewController.selectedViewController {
                    return topViewController(selectedViewController)
                }
            }
    
            if let splitViewController = baseViewController as? UISplitViewController where splitViewController.viewControllers.count == 1 {
                return topViewController(splitViewController.viewControllers[0])
            }
    
            if let presentedViewController = baseViewController?.presentedViewController {
                return topViewController(presentedViewController)
            }
    
            return baseViewController
        }
    }
    

    Simple usage:

    if let topViewController = UIApplication.topViewController() {
        //do sth with top view controller
    }
    
    0 讨论(0)
提交回复
热议问题