我遇到了几种情况,需要找到“最上层”的视图控制器(负责当前视图的视图控制器),但没有找到方法。
基本上,这个挑战是这样的:假设一个类不是视图控制器(或视图)[并且没有活动视图的地址],也没有传入最上面视图控制器的地址(或者比如导航控制器的地址),那么是否可能找到该视图控制器呢?(如果可以,怎么实现?)
或者,如果找不到它,是否可能找到最上层的视图?
我遇到了几种情况,需要找到“最上层”的视图控制器(负责当前视图的视图控制器),但没有找到方法。
基本上,这个挑战是这样的:假设一个类不是视图控制器(或视图)[并且没有活动视图的地址],也没有传入最上面视图控制器的地址(或者比如导航控制器的地址),那么是否可能找到该视图控制器呢?(如果可以,怎么实现?)
或者,如果找不到它,是否可能找到最上层的视图?
不确定这是否有助于您通过查找最顶层的视图控制器来完成所需的任务,但我正在尝试呈现一个新的视图控制器。但是,如果我的根视图控制器已经有了模态对话框,则会被阻止,因此我将使用以下代码循环到所有模态视图控制器的顶部:
UIViewController* parentController =[UIApplication sharedApplication].keyWindow.rootViewController;
while( parentController.presentedViewController &&
parentController != parentController.presentedViewController )
{
parentController = parentController.presentedViewController;
}
这对于从任何根视图控制器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];
之前的答案似乎没有处理 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
}
我认为Rajesh的解决方案几乎完美,但我认为从上到下遍历子视图更好,我改成了以下方式:
+ (UIViewController *)topViewController:(UIViewController *)viewController{
if (viewController.presentedViewController)
{
UIViewController *presentedViewController = viewController.presentedViewController;
return [self topViewController:presentedViewController];
}
else if ([viewController isKindOfClass:[UITabBarController class]])
{
UITabBarController *tabBarController = (UITabBarController *)viewController;
return [self topViewController:tabBarController.selectedViewController];
}
else if ([viewController isKindOfClass:[UINavigationController class]])
{
UINavigationController *navController = (UINavigationController *)viewController;
return [self topViewController:navController.visibleViewController];
}
// Handling UIViewController's added as subviews to some other views.
else {
NSInteger subCount = [viewController.view subviews].count - 1;
for (NSInteger index = subCount; index >=0 ; --index)
{
UIView *view = [[viewController.view subviews] objectAtIndex:index];
id subViewController = [view nextResponder]; // Key property which most of us are unaware of / rarely use.
if ( subViewController && [subViewController isKindOfClass:[UIViewController class]])
{
return [self topViewController:subViewController];
}
}
return viewController;
}
}
我认为这里可能有一件事被忽视了。也许更好的方法是将父视图控制器传递到使用视图控制器的函数中。如果您在视图层次结构中四处寻找顶部视图控制器,那么可能会违反模型层和UI层之间的分离,并且是一种代码异味。只是指出这一点,我也曾经这样做,然后意识到更简单的方法就是通过将模型操作返回到我具有对视图控制器的引用的UI层来将其传递给函数。
另一种解决方案依赖于响应链,这取决于第一响应者是什么,可能有效也可能无效:
示例伪代码:
+ (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;
}
我的问题有点不同,我在我的应用程序中使用SWRevealViewController。我使用了钟雨辰的答案,但它总是将topViewController返回为SWRevealViewController。对于那些正在使用SWRevealViewController或其他pod来开发侧边菜单的人来说,这是我对钟雨辰答案的扩展:
extension UIApplication {
class func topViewController() -> UIViewController? {
var topVC = shared.keyWindow!.rootViewController
while true {
if let presented = topVC?.presentedViewController {
topVC = presented
} else if let nav = topVC as? UINavigationController {
topVC = nav.visibleViewController
} else if let tab = topVC as? UITabBarController {
topVC = tab.selectedViewController
}else if let swRVC = topVC as? SWRevealViewController {
topVC = swRVC.frontViewController
} else {
break
}
}
return topVC
}
}
Swift 5
试一下这个
let topVisibleVC = UIApplication.shared.keyWindow?.rootViewController?.visibleViewController
你可以使用以下方法找到最顶层的视图控制器
NSArray *arrViewControllers=[[self navigationController] viewControllers];
UIViewController *topMostViewController=(UIViewController *)[arrViewControllers objectAtIndex:[arrViewControllers count]-1];
self
没有navigationController
属性。 - Hot Licks