我遇到了几种情况,需要找到“最上层”的视图控制器(负责当前视图的视图控制器),但没有找到方法。
基本上,这个挑战是这样的:假设一个类不是视图控制器(或视图)[并且没有活动视图的地址],也没有传入最上面视图控制器的地址(或者比如导航控制器的地址),那么是否可能找到该视图控制器呢?(如果可以,怎么实现?)
或者,如果找不到它,是否可能找到最上层的视图?
我遇到了几种情况,需要找到“最上层”的视图控制器(负责当前视图的视图控制器),但没有找到方法。
基本上,这个挑战是这样的:假设一个类不是视图控制器(或视图)[并且没有活动视图的地址],也没有传入最上面视图控制器的地址(或者比如导航控制器的地址),那么是否可能找到该视图控制器呢?(如果可以,怎么实现?)
或者,如果找不到它,是否可能找到最上层的视图?
我认为你需要结合已经被接受的答案和 @fishstix 的答案。
+ (UIViewController*) topMostController
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
return topController;
}
Swift 3.0+
func topMostController() -> UIViewController? {
guard let window = UIApplication.shared.keyWindow, let rootViewController = window.rootViewController else {
return nil
}
var topController = rootViewController
while let newTopController = topController.presentedViewController {
topController = newTopController
}
return topController
}
UINavigationController
并请求其 topViewController
,甚至可以检查 UITabBarController
并请求其 selectedViewController
。这将获取当前对用户可见的视图控制器。 - Tricertops- (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;
}
}
childViewControllers
。 - Awesome-oreturn [self topViewControllerWithRootViewController:navigationController.visibleViewController];
,则visibleViewController
本身会返回显示的视图控制器(如果有的话),即使它是UIAlertController
。对于需要避免UI警报控制器的人,请使用topViewController
而不是visibleViewController
。 - JohnykuttyiOS 4在UIWindow上引入了rootViewController属性:
[UIApplication sharedApplication].keyWindow.rootViewController;
不过,创建视图控制器后你需要自己设置它。
-[UINavigationController topViewController]
)。然后有“root”这个词,它是树的根(例如-[UIWindow rootViewController]
)。 - TricertopsUINavigationController
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+
->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
}
}
visibleViewController
,以明确它的功能。 - Jonny使用扩展获取 Swift 中的顶层视图控制器
代码:
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()
}
}
使用方法:
UIApplication.sharedApplication().keyWindow!.rootViewController!.topMostViewController()
为了完善Eric的answer(他遗漏了弹出窗口、导航控制器、选项卡控制器、作为其他视图控制器子视图添加时遍历的视图控制器),这是我的版本,返回当前可见的视图控制器:
=====================================================================
- (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];
这个答案包括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;
}
最新的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.shared.delegate
if let window = appDelegate!.window {
return window?.visibleViewController
}
return nil
}
可在任何地方使用,例如:
if let topVC = getTopViewController() {
}
switch
代替if else。3. 不确定是否需要静态函数,我认为你可以在第一个实例级变量中轻松完成此操作。4. 最好不要创建太多全局函数,但这是品味问题。您可以使用一行代码来实现全局函数的效果:UIApplication.sharedApplication().delegate?.window?.visibleViewController
。 - Jordan SmithUIViewController *c = [UIViewController topMostController];
使用以下扩展来获取当前可见的UIViewController
。适用于Swift 4.0及更高版本。
extension UIApplication {
class func topViewController(_ viewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = viewController as? UINavigationController {
return topViewController(nav.visibleViewController)
}
if let tab = viewController as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = viewController?.presentedViewController {
return topViewController(presented)
}
return viewController
}
}
如何使用?
let objViewcontroller = UIApplication.topViewController()
UINavigationController
和UITabBarController
的情况之前,难道不应该首先测试presentedViewController
吗?否则,如果一个视图控制器是从UINavigationController
或UITabBarController
模态呈现的,即使它是可见的视图控制器,它也不会被返回为顶部视图控制器。 - Drew