UIAlertController 下最顶层的 ViewController
Posted
技术标签:
【中文标题】UIAlertController 下最顶层的 ViewController【英文标题】:Top most ViewController under UIAlertController 【发布时间】:2016-03-29 12:36:18 【问题描述】:我正在使用以下扩展程序来查找top most ViewController。
如果出现警报,上面的代码会给出UIAlertController
。
如何获得顶视图控制器下 UIAlertController
?
【问题讨论】:
可以在这里找到好的答案:***.com/q/26554894/3050403 @Luda 你解决了这个问题吗.. 你能提供代码吗?我也面临同样的问题..谢谢! @SteveGear 不幸的是我不记得了。请检查下面的答案 【参考方案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,因为它存在于另一个窗口中!
所以如果topViewController
从keyWindow?.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
【讨论】:
以上是关于UIAlertController 下最顶层的 ViewController的主要内容,如果未能解决你的问题,请参考以下文章
带有呈现的 UIAlertController 的 UINavigationController 被另外解雇
不在视图控制器中时如何呈现 UIAlertController?
iOS开发 - 获取当前View最顶层的ViewController