从AppDelegate获取当前视图控制器?

60
有没有一种方式从AppDelegate获取当前视图控制器?我知道有rootViewController,但这不是我想要的。
11个回答

65

如果您的应用程序的根视图控制器是一个 UINavigationController,您可以这样做:

((UINavigationController*)appDelegate.window.rootViewController).visibleViewController;

同样地,如果这是一个UITabBarController,您可以这样做:

((UITabBarController*)appDelegate.window.rootViewController).selectedViewController;

当然,像这样显式转换是不好的。更好的方法是使用强类型自己捕获引用。


32

这可能会有所帮助

- (UIViewController *)topViewController{
  return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController *)topViewController:(UIViewController *)rootViewController
{
  if (rootViewController.presentedViewController == nil) {
    return rootViewController;
  }

  if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]]) {
    UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
    UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
    return [self topViewController:lastViewController];
  }

  UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
  return [self topViewController:presentedViewController];
}

Swift版本:

extension UIApplication {
    class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.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)
        }
        return base
    }
}

翻译来源: https://gist.github.com/snikch/3661188


25

16

制作扩展:

extension UIApplication {
    class func topViewController(base: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {
        if let nav = base as? UINavigationController {
            return topViewController(nav.visibleViewController)
        }
        if let tab = base as? UITabBarController {
            let moreNavigationController = tab.moreNavigationController

            if let top = moreNavigationController.topViewController where top.view.window != nil {
                return topViewController(top)
            } else if let selected = tab.selectedViewController {
                return topViewController(selected)
            }
        }
        if let presented = base?.presentedViewController {
            return topViewController(presented)
        }
        return base
    }
}

使用方法:

if let rootViewController = UIApplication.topViewController() {
    //do sth with root view controller
}

这个答案解决了苹果的高级NSOperations示例类中一个令人烦恼的问题。如果发生错误,最上层的视图控制器是唯一能够呈现警报的视图控制器。我可能会将其迭代而不是递归,因为我比较老派,但这比盲目地使用UIApplication.sharedApplication().keyWindow?.rootViewController要好得多。 - Bob Wakefield

12

获取appDelegate对象:

MyAppDelegate *tmpDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];

正如beryllium建议的那样,您可以使用UINavigationController的属性来访问当前的视图控制器。

因此,代码将如下所示:

id myCurrentController = tmpDelegate.myNavigationController.topViewController;
或者:
NSArray *myCurrentViewControllers = tmpDelegate.myNavigationController.viewControllers;

9
您可以通过查找其presentedViewController从rootViewController获取当前视图控制器,例如:
UIViewController *parentViewController = [[[UIApplication sharedApplication] delegate] window].rootViewController;

while (parentViewController.presentedViewController != nil){
    parentViewController = parentViewController.presentedViewController;
}
UIViewController *currentViewController = parentViewController;

它对我有效。希望能帮到你 :)

5

对于那些不使用UINavigationController而是使用默认视图控制器UIViewController的人,您可以在AppDelegate中使用以下代码检查哪个视图控制器处于活动状态(或已呈现):

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    if let rootViewController = self.window!.rootViewController {
        if let presentedViewController = rootViewController.presentedViewController {
            return presentedViewController.supportedInterfaceOrientations()
        }
    } // Else current view controller is DefaultViewController

    return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}

正如您所看到的,我正在检查当前视图控制器,以支持特定视图控制器的不同界面方向。对于其他有兴趣使用此方法来支持特定方向的人,应在需要特定方向的每个视图控制器中放置以下内容。

override func supportedInterfaceOrientations() -> Int {
    return Int(UIInterfaceOrientationMask.All.rawValue)
} 

注意: 这段代码使用的是Swift 1.2


更好的方法是将 if let 改为 while let,这样它就能够获取最顶部的值。 - mginn

5

基于 A.G 的方案,使用 Swift 4+ 语法的 UIApplication 扩展。

public extension UIApplication {

    class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let nav = base as? UINavigationController {
            return topViewController(base: nav.visibleViewController)
        }
        if let tab = base as? UITabBarController {
            let moreNavigationController = tab.moreNavigationController

            if let top = moreNavigationController.topViewController, top.view.window != nil {
                return topViewController(base: top)
            } else if let selected = tab.selectedViewController {
                return topViewController(base: selected)
            }
        }
        if let presented = base?.presentedViewController {
            return topViewController(base: presented)
        }
        return base
    }
}

用法示例:

if let rootViewController = UIApplication.topViewController() {
     //do something with rootViewController
}

太棒了!它也适用于选项卡栏,因为我只是在寻找选项卡栏。 - Darshit Mendapara

4

快速解决方案:

 self.window.rootViewController.presentedViewController. 

这应该能帮到你得到所需的内容。

这种方法仅适用于self是UIView或类似视图,而不适用于抽象类。 - Duncan Babbage

0

经常需要检索当前显示的视图控制器。这可能意味着当前UINavigationController堆栈顶部的视图控制器,当前呈现的视图控制器等等。因此,我编写了这个函数,它大多数情况下可以找到它,并且您可以在UIViewController扩展中使用它。

Swift 3代码:

func currentViewController(
_ viewController: UIViewController? =
    UIApplication.shared.keyWindow?.rootViewController)
        -> UIViewController? {
    guard let viewController =
    viewController else { return nil }

    if let viewController =
        viewController as? UINavigationController {
        if let viewController =
            viewController.visibleViewController {
            return currentViewController(viewController)
        } else {
            return currentViewController(
                viewController.topViewController)
        }
    } else if let viewController =
            viewController as? UITabBarController {
        if let viewControllers =
            viewController.viewControllers,
            viewControllers.count > 5,
            viewController.selectedIndex >= 4 {
            return currentViewController(
                viewController.moreNavigationController)
        } else {
            return currentViewController(
                viewController.selectedViewController)
        }
    } else if let viewController =
            viewController.presentedViewController {
        return viewController
    } else if viewController.childViewControllers.count > 0 {
        return viewController.childViewControllers[0]
    } else {
        return viewController
    }
}

调用方法:currentViewController()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接