【问题标题】:Top most ViewController under UIAlertControllerUIAlertController 下最顶层的 ViewController
【发布时间】:2016-03-29 12:36:18
【问题描述】:

我正在使用以下扩展程序来查找top most ViewController。 如果出现警报,上面的代码会给出UIAlertController。 如何获得顶视图控制器 UIAlertController

【问题讨论】:

  • 可以在这里找到好的答案:stackoverflow.com/q/26554894/3050403
  • @Luda 你解决了这个问题吗.. 你能提供代码吗?我也面临同样的问题..谢谢!
  • @SteveGear 不幸的是我不记得了。请检查下面的答案

标签: ios swift uiviewcontroller uialertcontroller


【解决方案1】:

创建一个如下所示的 UIApplication 扩展,UIApplication.topViewController() 将返回UIAlertController 下最顶部的UIViewController

iOS 13+

extension UIApplication {

    class func topViewController(controller: UIViewController? = UIApplication.shared.windows.first?.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)
        }
        if let alert = controller as? UIAlertController {
            if let navigationController = alert.presentingViewController as? UINavigationController {
                return navigationController.viewControllers.last
            }
            return alert.presentingViewController
        }
        return controller
    }

}

iOS 12-

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)
        }
        if let alert = controller as? UIAlertController {
            if let navigationController = alert.presentingViewController as? UINavigationController {
                return navigationController.viewControllers.last
            }
            return alert.presentingViewController
        }
        return controller
    }

}

【讨论】:

    【解决方案2】:

    您可以使用presentingViewController 属性获取UIAlertController 的父控制器

    extension UIApplication {
      class func topViewController(base: UIViewController? = (UIApplication.sharedApplication().delegate as! AppDelegate).window?.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 alert = base as? UIAlertController {
          if let presenting = alert.presentingViewController {
            return topViewController(base: presenting)
          }
        }
        if let presented = base?.presentedViewController {
          return topViewController(base: presented)
        }
        return base
      }
    }
    

    在您的代码中使用这些更改,未在 XCode 上测试。

    【讨论】:

    • 无限递归
    • 我们只需要找出 UIAlertController 的祖先是谁
    • 对不起,它是 UIAlertController 而不是 UIAlertViewController。更新了我的答案。
    • 无限递归仍然发生
    • @BrianOgden 您能否确认您是否没有使用任何第三方控制器作为您的window.rootViewController 像任何侧边菜单之类的东西?
    【解决方案3】:

    我使用这个扩展来获取 UIAlertController 下最顶层的视图控制器,基本上我所做的就是在找到一个 UIAlertController 时停止寻找顶层视图控制器。

    extension UIApplication {
    
    var topViewController: UIViewController? {
        var viewController = keyWindow?.rootViewController
        guard viewController != nil else { return nil }
        var presentedViewController = viewController?.presentedViewController
        while presentedViewController != nil, !(presentedViewController is UIAlertController) {
            switch presentedViewController {
            case let navagationController as UINavigationController:
                viewController = navagationController.viewControllers.last
            case let tabBarController as UITabBarController:
                viewController = tabBarController.selectedViewController
            default:
                viewController = viewController?.presentedViewController
            }
            presentedViewController = viewController?.presentedViewController
        }
        return viewController
    }
    

    }

    【讨论】:

      【解决方案4】:

      您可以检查下一个 viewController 是否为UIAlertController,如果是则返回其父级。像这样的:

      if let presented = base as? UIAlertController {
        return base.presentingViewController
      }
      

      在返回之前将其添加到您使用的扩展中。

      更新

      extension UIApplication {
         class func topViewController(base: UIViewController? =    (UIApplication.sharedApplication().delegate as! AppDelegate).window?.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)
            }
      
            if let alert = base as? UIAlertController {
               return alert.presentingViewController
            }
      
            return base
         }
      }
      

      【讨论】:

      • base.parentViewController 为 nil :(
      • 不...基础是 UIAlertController。不是基础?.presentedViewController
      • 你确定把它放在if let presented = base?.presentedViewController {上面吗?
      • 我做了,如果调试器没有输入这个。但是当我添加 if let present = base as? UIAlertController { 它确实进入了。这意味着 UIAlertController 是基础
      • base 不是 UIAlertController。但是 base!.presentedViewController 是我们只需要找出谁是 UIAlertController 的祖先
      【解决方案5】:

      我认为你想在当前顶部可见的 VC 上推送一个新的 VC,它是一个 UIAlertController,然后这个 UIAlertController 将立即消失,导致推送的新 VC 也被关闭。最后,你不能推送新的 VC。

      问题是,如果你新建了一个 UIAlertView,然后调用show,Cocoa Touch 会初始化一个新窗口,rootViewController 是 UIApplicationRotationFollowingController,presentingViewController 是 UIAlertController。所以不能遍历 UIAlertController 下最顶层的 VC,因为它存在于另一个窗口中!

      所以如果topViewControllerkeyWindow?.rootViewController遍历,找到UIAlertController,再次调用topViewController但是从window遍历你想要的,比如(UIApplication.sharedApplication().delegate as! AppDelegate).window?.rootViewController

      【讨论】:

        【解决方案6】:

        这是正确的:

            func firstApplicableViewController() -> UIViewController? {
                if (self is UITabBarController) {
                    let tabBarController = self as? UITabBarController
                    return tabBarController?.selectedViewController?.firstApplicableViewController()
                } else if (self is UINavigationController) {
                    let navigationController = self as? UINavigationController
                    return navigationController?.visibleViewController?.firstApplicableViewController()
                } else if (self is UIAlertController) {
                    let presentingViewController: UIViewController = self.presentingViewController!
                    return presentingViewController.firstApplicableViewController()
                } else if self.presentedViewController != nil {
                    let presentedViewController: UIViewController = self.presentedViewController!
                    if (presentedViewController is UIAlertController) {
                        return self
                    } else {
                        return presentedViewController.firstApplicableViewController()
                    }
                } else {
                    return self
                }
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-25
          • 2011-05-03
          相关资源
          最近更新 更多