我遇到了一些情况,现在,它将是方便的,能够找到“最顶层”的视图控制器(一个负责当前视图),但还没有找到一种方法。
基本上,挑战是这样的:给定一个在一个类中执行,这个类不是一个视图控制器(或一个视图)[并且没有活动视图的地址],并且没有传递最顶层视图控制器的地址(或者,比如说,导航控制器的地址),是否有可能找到那个视图控制器?(如果是的话,是怎么做到的?)
或者,如果找不到,有没有可能找到最高处的风景?
我遇到了一些情况,现在,它将是方便的,能够找到“最顶层”的视图控制器(一个负责当前视图),但还没有找到一种方法。
基本上,挑战是这样的:给定一个在一个类中执行,这个类不是一个视图控制器(或一个视图)[并且没有活动视图的地址],并且没有传递最顶层视图控制器的地址(或者,比如说,导航控制器的地址),是否有可能找到那个视图控制器?(如果是的话,是怎么做到的?)
或者,如果找不到,有没有可能找到最高处的风景?
当前回答
另一个解决方案依赖于responder链,它可能工作,也可能不工作,这取决于第一个responder是什么:
获取第一个响应器。 获取与第一个responder相关联的UIViewController。
示例伪代码:
+ (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;
}
其他回答
这是对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;
}
UIViewController *cont是一个辅助函数。
现在你所需要做的就是调用topMostController()和最顶端的UIViewController应该被返回!
Swift 4.2中一个简洁而全面的解决方案,考虑了UINavigationControllers, UITabBarControllers, presenting和子视图控制器:
extension UIViewController {
func topmostViewController() -> UIViewController {
if let navigationVC = self as? UINavigationController,
let topVC = navigationVC.topViewController {
return topVC.topmostViewController()
}
if let tabBarVC = self as? UITabBarController,
let selectedVC = tabBarVC.selectedViewController {
return selectedVC.topmostViewController()
}
if let presentedVC = presentedViewController {
return presentedVC.topmostViewController()
}
if let childVC = children.last {
return childVC.topmostViewController()
}
return self
}
}
extension UIApplication {
func topmostViewController() -> UIViewController? {
return keyWindow?.rootViewController?.topmostViewController()
}
}
用法:
let viewController = UIApplication.shared.topmostViewController()
之前的答案似乎不能处理rootController是UITabBarController或UINavigationController的情况。
下面是swift中适用于这些情况的函数:
func getCurrentView() -> UIViewController?
{
if let window = UIApplication.sharedApplication().keyWindow, var currentView: UIViewController = window.rootViewController
{
while (currentView.presentedViewController != nil)
{
if let presented = currentView.presentedViewController
{
currentView = presented
}
}
if currentView is UITabBarController
{
if let visible = (currentView as! UITabBarController).selectedViewController
{
currentView = visible;
}
}
if currentView is UINavigationController
{
if let visible = (currentView as! UINavigationController).visibleViewController
{
currentView = visible;
}
}
return currentView
}
return nil
}
这个答案包含了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;
}
另一个解决方案依赖于responder链,它可能工作,也可能不工作,这取决于第一个responder是什么:
获取第一个响应器。 获取与第一个responder相关联的UIViewController。
示例伪代码:
+ (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;
}