首页 文章

iPhone - 如何找到最顶层的视图控制器

提问于
浏览
224

我现在遇到了几个案例,它们可以方便地找到“最顶层”的视图控制器(负责当前视图的控制器),但还没有找到办法 .

基本上挑战是:假设一个是 executing in a class that is not a view controller (或视图) [and does not have the address of an active view] 并且还没有传递最顶层视图控制器的地址(或者说,导航控制器的地址),是否可以找到该视图控制器? (如果是这样,怎么样?)

或者,如果失败了,是否有可能找到最顶层的视图?

30 回答

  • 148

    iOS 4在UIWindow上引入了rootViewController属性:

    [UIApplication sharedApplication].keyWindow.rootViewController;
    

    您需要在创建视图控制器后自己设置它 .

  • 0

    我认为你需要一个接受的答案和@ fishstix的组合

    + (UIViewController*) topMostController
    {
        UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
    
        while (topController.presentedViewController) {
            topController = topController.presentedViewController;
        }
    
        return topController;
    }
    

    Swift 3.0+

    let rootViewController = UIApplication.shared.keyWindow?.rootViewController
    
  • 38

    要完成JonasG的answer(在遍历时遗漏了标签栏控制器),这是我返回当前可见视图控制器的版本:

    - (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;
        }
    }
    
  • 27

    一个完整的非递归版本,负责不同的场景:

    • 视图控制器正在呈现另一个视图

    • 视图控制器是 UINavigationController

    • 视图控制器是 UITabBarController

    Objective-C

    UIViewController *topViewController = self.window.rootViewController;
     while (true)
     {
         if (topViewController.presentedViewController) {
             topViewController = topViewController.presentedViewController;
         } else if ([topViewController isKindOfClass:[UINavigationController class]]) {
             UINavigationController *nav = (UINavigationController *)topViewController;
             topViewController = nav.topViewController;
         } else if ([topViewController isKindOfClass:[UITabBarController class]]) {
             UITabBarController *tab = (UITabBarController *)topViewController;
             topViewController = tab.selectedViewController;
         } else {
             break;
         }
     }
    

    Swift 4+

    extension UIWindow {
        func topViewController() -> UIViewController? {
            var top = self.rootViewController
            while true {
                if let presented = top?.presentedViewController {
                    top = presented
                } else if let nav = top as? UINavigationController {
                    top = nav.visibleViewController
                } else if let tab = top as? UITabBarController {
                    top = tab.selectedViewController
                } else {
                    break
                }
            }
            return top
        }
    }
    
  • 0

    使用扩展获取Swift的最顶层视图控制器

    Code:

    extension UIViewController {
        @objc func topMostViewController() -> UIViewController {
            // Handling Modal views
            if let presentedViewController = self.presentedViewController {
                return presentedViewController.topMostViewController()
            }
            // Handling UIViewController's added as subviews to some other views.
            else {
                for view in self.view.subviews
                {
                    // Key property which most of us are unaware of / rarely use.
                    if let subViewController = view.next {
                        if subViewController is UIViewController {
                            let viewController = subViewController as! UIViewController
                            return viewController.topMostViewController()
                        }
                    }
                }
                return self
            }
        }
    }
    
    extension UITabBarController {
        override func topMostViewController() -> UIViewController {
            return self.selectedViewController!.topMostViewController()
        }
    }
    
    extension UINavigationController {
        override func topMostViewController() -> UIViewController {
            return self.visibleViewController!.topMostViewController()
        }
    }
    

    Usage:

    UIApplication.sharedApplication().keyWindow!.rootViewController!.topMostViewController()
    
  • 2

    要完成Eric的answer(他们在浏览时遗漏了弹出窗口,导航控制器,tabbarcontrollers,视图控制器作为子视图添加到其他视图控制器),这是我返回当前可见视图控制器的版本:

    ================================================== ===================

    - (UIViewController*)topViewController {
        return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
    }
    
    - (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)viewController {
        if ([viewController isKindOfClass:[UITabBarController class]]) {
            UITabBarController* tabBarController = (UITabBarController*)viewController;
            return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
        } else if ([viewController isKindOfClass:[UINavigationController class]]) {
            UINavigationController* navContObj = (UINavigationController*)viewController;
            return [self topViewControllerWithRootViewController:navContObj.visibleViewController];
        } else if (viewController.presentedViewController && !viewController.presentedViewController.isBeingDismissed) {
            UIViewController* presentedViewController = viewController.presentedViewController;
            return [self topViewControllerWithRootViewController:presentedViewController];
        }
        else {
            for (UIView *view in [viewController.view subviews])
            {
                id subViewController = [view nextResponder];
                if ( subViewController && [subViewController isKindOfClass:[UIViewController class]])
                {
                    if ([(UIViewController *)subViewController presentedViewController]  && ![subViewController presentedViewController].isBeingDismissed) {
                        return [self topViewControllerWithRootViewController:[(UIViewController *)subViewController presentedViewController]];
                    }
                }
            }
            return viewController;
        }
    }
    

    ================================================== ===================

    现在你需要做的就是获得最顶层的视图控制器,调用上面的方法如下:

    UIViewController *topMostViewControllerObj = [self topViewController];
    
  • 1

    这个答案包括 childViewControllers 并维护一个干净和可读的实现 .

    + (UIViewController *)topViewController
    {
        UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
    
        return [rootViewController topVisibleViewController];
    }
    
    - (UIViewController *)topVisibleViewController
    {
        if ([self isKindOfClass:[UITabBarController class]])
        {
            UITabBarController *tabBarController = (UITabBarController *)self;
            return [tabBarController.selectedViewController topVisibleViewController];
        }
        else if ([self isKindOfClass:[UINavigationController class]])
        {
            UINavigationController *navigationController = (UINavigationController *)self;
            return [navigationController.visibleViewController topVisibleViewController];
        }
        else if (self.presentedViewController)
        {
            return [self.presentedViewController topVisibleViewController];
        }
        else if (self.childViewControllers.count > 0)
        {
            return [self.childViewControllers.lastObject topVisibleViewController];
        }
    
        return self;
    }
    
  • 3

    我最近在我的一个项目中得到了这种情况,当网络状态发生变化时,需要显示控制器显示的通知视图以及类型(UINavigationController,经典控制器或自定义视图控制器) .

    所以我juste发布了我的代码,这很简单并且实际上基于协议,因此它对于每种类型的容器控制器都是灵活的 . 它似乎与最后的答案有关,但是以一种非常灵活的方式 .

    你可以在这里获取代码:PPTopMostController

    并获得最高控制器使用

    UIViewController *c = [UIViewController topMostController];
    
  • 8

    这是对Eric的回答的改进:

    UIViewController *_topMostController(UIViewController *cont) {
        UIViewController *topController = cont;
    
        while (topController.presentedViewController) {
            topController = topController.presentedViewController;
        }
    
        if ([topController isKindOfClass:[UINavigationController class]]) {
            UIViewController *visible = ((UINavigationController *)topController).visibleViewController;
            if (visible) {
                topController = visible;
            }
        }
    
        return (topController != cont ? topController : nil);
    }
    
    UIViewController *topMostController() {
        UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
    
        UIViewController *next = nil;
    
        while ((next = _topMostController(topController)) != nil) {
            topController = next;
        }
    
        return topController;
    }
    

    _topMostController(UIViewController *cont) 是辅助函数 .

    现在您需要做的就是调用 topMostController() 并返回最顶层的UIViewController!

  • 0
    - (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;
        }
    }
    
  • 1
    @implementation UIWindow (Extensions)
    
    - (UIViewController*) topMostController
    {
        UIViewController *topController = [self rootViewController];
    
        while (topController.presentedViewController) {
            topController = topController.presentedViewController;
        }
    
        return topController;
    }
    
    @end
    
  • 19

    这是我对此的看法 . 感谢@Stakenborg指出了跳过让UIAlertView成为最顶级控制器的方法

    -(UIWindow *) returnWindowWithWindowLevelNormal
    {
        NSArray *windows = [UIApplication sharedApplication].windows;
        for(UIWindow *topWindow in windows)
        {
            if (topWindow.windowLevel == UIWindowLevelNormal)
                return topWindow;
        }
        return [UIApplication sharedApplication].keyWindow;
    }
    
    -(UIViewController *) getTopMostController
    {
        UIWindow *topWindow = [UIApplication sharedApplication].keyWindow;
        if (topWindow.windowLevel != UIWindowLevelNormal)
        {
            topWindow = [self returnWindowWithWindowLevelNormal];
        }
    
        UIViewController *topController = topWindow.rootViewController;
        if(topController == nil)
        {
            topWindow = [UIApplication sharedApplication].delegate.window;
            if (topWindow.windowLevel != UIWindowLevelNormal)
            {
                topWindow = [self returnWindowWithWindowLevelNormal];
            }
            topController = topWindow.rootViewController;
        }
    
        while(topController.presentedViewController)
        {
            topController = topController.presentedViewController;
        }
    
        if([topController isKindOfClass:[UINavigationController class]])
        {
            UINavigationController *nav = (UINavigationController*)topController;
            topController = [nav.viewControllers lastObject];
    
            while(topController.presentedViewController)
            {
                topController = topController.presentedViewController;
            }
        }
    
        return topController;
    }
    
  • 7

    对于最新的Swift版本:
    创建一个文件,将其命名为 UIWindowExtension.swift 并粘贴以下代码段:

    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
    }
    

    在任何地方使用它:

    if let topVC = getTopViewController() {
    
    }
    
  • 7

    Swift中 UIApplication 的简单扩展:

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

    用法简单:

    if let topViewController = UIApplication.topViewController() {
        //do sth with top view controller
    }
    
  • 2

    这对我有用 .

    我发现有时控制器在关键窗口上是零,因为keyWindow是一些操作系统,如警报等 .

    + (UIViewController*)topMostController
     {
         UIWindow *topWndow = [UIApplication sharedApplication].keyWindow;
         UIViewController *topController = topWndow.rootViewController;
    
         if (topController == nil)
         {
             // The windows in the array are ordered from back to front by window level; thus,
             // the last window in the array is on top of all other app windows.
             for (UIWindow *aWndow in [[UIApplication sharedApplication].windows reverseObjectEnumerator])
             {
                 topController = aWndow.rootViewController;
                 if (topController)
                     break;
             }
         }
    
         while (topController.presentedViewController) {
             topController = topController.presentedViewController;
         }
    
         return topController;
     }
    
  • 3

    扩展@ Eric的答案,你需要注意keyWindow实际上是你想要的窗口 . 例如,如果您在警报视图中点击某些内容后尝试使用此方法,则keyWindow实际上将成为警报的窗口,这无疑会给您带来问题 . 当通过警报处理深度链接并导致SIGABRT没有堆栈跟踪时,这发生在我的野外 . 要调试的总婊子 .

    这是我现在使用的代码:

    - (UIViewController *)getTopMostViewController {
        UIWindow *topWindow = [UIApplication sharedApplication].keyWindow;
        if (topWindow.windowLevel != UIWindowLevelNormal) {
            NSArray *windows = [UIApplication sharedApplication].windows;
            for(topWindow in windows)
            {
                if (topWindow.windowLevel == UIWindowLevelNormal)
                    break;
            }
        }
    
        UIViewController *topViewController = topWindow.rootViewController;
    
        while (topViewController.presentedViewController) {
            topViewController = topViewController.presentedViewController;
        }
    
        return topViewController;
    }
    

    随意从这个问题的其他答案中检索您喜欢的顶视图控制器的风格 .

  • 13

    替代Swift解决方案:

    static func topMostController() -> UIViewController {
        var topController = UIApplication.sharedApplication().keyWindow?.rootViewController
        while (topController?.presentedViewController != nil) {
            topController = topController?.presentedViewController
        }
    
        return topController!
    }
    
  • 7

    又一个Swift解决方案

    func topController() -> UIViewController? {
    
        // recursive follow
        func follow(from:UIViewController?) -> UIViewController? {
            if let to = (from as? UITabBarController)?.selectedViewController {
                return follow(to)
            } else if let to = (from as? UINavigationController)?.visibleViewController {
                return follow(to)
            } else if let to = from?.presentedViewController {
                return follow(to)
            }
            return from
        }
    
        let root = UIApplication.sharedApplication().keyWindow?.rootViewController
    
        return follow(root)
    
    }
    
  • 3

    这个解决方案是最完整的 . 它需要考虑:UINavigationController UIPageViewController UITabBarController和顶视图控制器中最顶层的视图控制器

    这个例子是在Swift 3中 .

    有3个重载

    //Get the topmost view controller for the current application.
    public func MGGetTopMostViewController() -> UIViewController?  {
    
        if let currentWindow:UIWindow = UIApplication.shared.keyWindow {
            return MGGetTopMostViewController(fromWindow: currentWindow)
        }
    
        return nil
    }
    
    //Gets the topmost view controller from a specific window.
    public func MGGetTopMostViewController(fromWindow window:UIWindow) -> UIViewController? {
    
        if let rootViewController:UIViewController = window.rootViewController
        {
            return MGGetTopMostViewController(fromViewController:  rootViewController)
        }
    
        return nil
    }
    
    
    //Gets the topmost view controller starting from a specific UIViewController
    //Pass the rootViewController into this to get the apps top most view controller
    public func MGGetTopMostViewController(fromViewController viewController:UIViewController) -> UIViewController {
    
        //UINavigationController
        if let navigationViewController:UINavigationController = viewController as? UINavigationController {
            let viewControllers:[UIViewController] = navigationViewController.viewControllers
            if navigationViewController.viewControllers.count >= 1 {
                return MGGetTopMostViewController(fromViewController: viewControllers[viewControllers.count - 1])
            }
        }
    
        //UIPageViewController
        if let pageViewController:UIPageViewController = viewController as? UIPageViewController {
            if let viewControllers:[UIViewController] = pageViewController.viewControllers {
                if viewControllers.count >= 1 {
                    return MGGetTopMostViewController(fromViewController: viewControllers[0])
                }
            }
        }
    
        //UITabViewController
        if let tabBarController:UITabBarController = viewController as? UITabBarController {
            if let selectedViewController:UIViewController = tabBarController.selectedViewController {
                return MGGetTopMostViewController(fromViewController: selectedViewController)
            }
        }
    
        //Lastly, Attempt to get the topmost presented view controller
        var presentedViewController:UIViewController! = viewController.presentedViewController
        var nextPresentedViewController:UIViewController! = presentedViewController?.presentedViewController
    
        //If there is a presented view controller, get the top most prensentedViewController and return it.
        if presentedViewController != nil {
            while nextPresentedViewController != nil {
    
                //Set the presented view controller as the next one.
                presentedViewController = nextPresentedViewController
    
                //Attempt to get the next presented view controller
                nextPresentedViewController = presentedViewController.presentedViewController
            }
            return presentedViewController
        }
    
        //If there is no topmost presented view controller, return the view controller itself.
        return viewController
    }
    
  • 0

    伟大的解决方案Swift,在AppDelegate中实现

    func getTopViewController()->UIViewController{
        return topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
    }
    func topViewControllerWithRootViewController(rootViewController:UIViewController)->UIViewController{
        if rootViewController is UITabBarController{
            let tabBarController = rootViewController as! UITabBarController
            return topViewControllerWithRootViewController(tabBarController.selectedViewController!)
        }
        if rootViewController is UINavigationController{
            let navBarController = rootViewController as! UINavigationController
            return topViewControllerWithRootViewController(navBarController.visibleViewController)
        }
        if let presentedViewController = rootViewController.presentedViewController {
            return topViewControllerWithRootViewController(presentedViewController)
        }
        return rootViewController
    }
    
  • 1

    我认为大多数答案都完全忽略 UINavigationViewController ,所以我通过以下实现处理了这个用例 .

    + (UIViewController *)topMostController {
        UIViewController * topController = [UIApplication sharedApplication].keyWindow.rootViewController;
        while (topController.presentedViewController || [topController isMemberOfClass:[UINavigationController class]]) {
            if([topController isMemberOfClass:[UINavigationController class]]) {
                topController = [topController childViewControllers].lastObject;
            } else {
                topController = topController.presentedViewController;
            }
        }
    
        return topController;
    }
    
  • 24

    不确定这是否有助于你通过找到最顶层的视图控制器来完成你想要完成的任务,但我试图提出一个新的视图控制器,但如果我的根视图控制器已经有一个模态对话框,它将被阻止,所以我将使用此代码循环到所有模态视图控制器的顶部:

    UIViewController* parentController =[UIApplication sharedApplication].keyWindow.rootViewController;
    
    while( parentController.presentedViewController &&
           parentController != parentController.presentedViewController )
    {
        parentController = parentController.presentedViewController;
    }
    
  • 387

    迅速:

    extension UIWindow {
    
    func visibleViewController() -> UIViewController? {
        if let rootViewController: UIViewController  = self.rootViewController {
            return UIWindow.getVisibleViewControllerFrom(rootViewController)
        }
        return nil
    }
    
    class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
    if vc.isKindOfClass(UINavigationController.self) {
    
        let navigationController = vc as UINavigationController
        return UIWindow.getVisibleViewControllerFrom( navigationController.visibleViewController)
    
    } else if vc.isKindOfClass(UITabBarController.self) {
    
        let tabBarController = vc as UITabBarController
        return UIWindow.getVisibleViewControllerFrom(tabBarController.selectedViewController!)
    
    } else {
    
        if let presentedViewController = vc.presentedViewController {
    
            return UIWindow.getVisibleViewControllerFrom(presentedViewController.presentedViewController!)
    
        } else {
    
            return vc;
        }
    }
    }
    

    用法:

    if let topController = window.visibleViewController() {
                println(topController)
            }
    
  • 1

    下面两个函数可以帮助在Stack of view控制器上找到topViewController . 您可能需要稍后进行自定义,但是对于此代码来说,了解topViewController或viewControllers堆栈的概念非常棒 .

    - (UIViewController*)findTopViewController {
    
      id  topControler  = [self topMostController];
    
      UIViewController* topViewController;
      if([topControler isKindOfClass:[UINavigationController class]]) {
            topViewController = [[(UINavigationController*)topControler viewControllers] lastObject];
       } else if ([topControler isKindOfClass:[UITabBarController class]]) {
            //Here you can get reference of top viewcontroller from stack of viewcontrollers on UITabBarController
      } else {
            //topController is a preented viewController
            topViewController = (UIViewController*)topControler;
      }
        //NSLog(@"Top ViewController is: %@",NSStringFromClass([topController class]));
        return topViewController;
    }
    
    - (UIViewController*)topMostController
    {
        UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
    
        while (topController.presentedViewController) {
            topController = topController.presentedViewController;
        }
        //NSLog(@"Top View is: %@",NSStringFromClass([topController class]));
        return topController;
    }
    

    您可以使用[viewController Class]方法找出viewController的类类型 .

  • 3

    另一个Swift解决方案

    extension UIViewController {
        static var topmostViewController: UIViewController? {
            return UIApplication.sharedApplication().keyWindow?.topmostViewController
        }
    
        var topmostViewController: UIViewController? {
            return presentedViewController?.topmostViewController ?? self
        }
    }
    
    extension UINavigationController {
        override var topmostViewController: UIViewController? {
            return visibleViewController?.topmostViewController
        }
    }
    
    extension UITabBarController {
        override var topmostViewController: UIViewController? {
            return selectedViewController?.topmostViewController
        }
    }
    
    extension UIWindow {
        var topmostViewController: UIViewController? {
            return rootViewController?.topmostViewController
        }
    }
    
  • 7

    很多这些答案都是不完整的 . 虽然这是在Objective-C中,但这是我现在可以组合在一起的所有这些的最佳编译,作为非递归块:

    ...... Link to gist ,如果它被修改:https://gist.github.com/benguild/0d149bb3caaabea2dac3d2dca58c0816

    ... Code 供参考/比较:

    UIViewController *(^topmostViewControllerForFrontmostNormalLevelWindowBlock)(void)=^UIViewController * // NOTE: Adapted from various stray answers here: https://stackoverflow.com/questions/6131205/iphone-how-to-find-topmost-view-controller/20515681
    {
        __block UIViewController *viewController;
    
        [[[[[UIApplication sharedApplication] windows] reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop)
        {
            if ([window windowLevel]==UIWindowLevelNormal)
            {
                viewController=[window rootViewController];
                ////
    
                *stop=YES;
    
            }
    
        } ];
    
        while (viewController)
        {
            if ([viewController isKindOfClass:[UITabBarController class]])
            {
                viewController=[(UITabBarController *)viewController selectedViewController];
    
            }
            else if ([viewController isKindOfClass:[UINavigationController class]])
            {
                viewController=[(UINavigationController *)viewController visibleViewController];
    
            }
            else if ([viewController presentedViewController] && ![[viewController presentedViewController] isBeingDismissed])
            {
                viewController=[viewController presentedViewController];
    
            }
            else if ([[viewController childViewControllers] count]>0)
            {
                viewController=[[viewController childViewControllers] lastObject];
    
            }
            else
            {
                __block BOOL needsRepeat=NO;
    
                [[[[[viewController view] subviews] reverseObjectEnumerator] allObjects] enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull view, NSUInteger idx, BOOL * _Nonnull stop)
                {
                    if ([[view nextResponder] isKindOfClass:[UIViewController class]])
                    {
                        viewController=(UIViewController *)[view nextResponder];
    
                        needsRepeat=YES;
                        ////
    
                        *stop=YES;
    
                    }
    
                } ];
    
                if (!needsRepeat)
                {
                    break;
    
                }
    
            }
    
        }
    
        return viewController;
    
    };
    
  • 3

    如果根控制器是导航控制器,找到顶部可见控制器的正确方法是:

    UIViewController *rootVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
    if ([rootVC respondsToSelector:@selector(visibleViewController)])
    {
        UIViewController *topVC = [(UINavigationController *)rootVC visibleViewController];
        // do your thing with topVC
    }
    

    这是UINavigationController.h的摘录:

    @property(nonatomic,readonly,retain) UIViewController *topViewController; // The top view controller on the stack.
    @property(nonatomic,readonly,retain) UIViewController *visibleViewController; // Return modal view controller if it exists. Otherwise the top view controller.
    
  • 75

    这非常适合从任何根视图控件中查找顶部viewController 1

    + (UIViewController *)topViewControllerFor:(UIViewController *)viewController
    {
        if(!viewController.presentedViewController)
            return viewController;
        return [MF5AppDelegate topViewControllerFor:viewController.presentedViewController];
    }
    
    /* View Controller for Visible View */
    
    AppDelegate *app = [UIApplication sharedApplication].delegate;
    UIViewController *visibleViewController = [AppDelegate topViewControllerFor:app.window.rootViewController];
    
  • 11

    你可以通过使用找到最顶层的视图控制器

    NSArray *arrViewControllers=[[self navigationController] viewControllers];
    UIViewController *topMostViewController=(UIViewController *)[arrViewControllers objectAtIndex:[arrViewControllers count]-1];
    
  • 1

    另一种解决方案依赖于响应者链,根据第一响应者的不同,响应者链可能会或可能不会起作用:

    伪代码示例:

    + (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;
    }
    

相关问题