从应用委托获取当前视图控制器(模式是可能的)



我知道要从应用程序委托获取当前视图控制器,我可以使用为应用程序设置的 navigationController 属性。但是,在我的应用程序中的许多地方都可能出现模式导航控制器。有没有办法从应用委托中检测到这一点,因为当前导航控制器将与应用委托持有引用的导航控制器不同?

根据此处的要点,我创建了一个类别来获取最顶层的视图控制器,这样调用[[UIApplication sharedApplication] topMostViewController]将为您提供应用中最顶层的视图控制器。

这在iOS 8中特别有用,其中UIAlertViewUIActionSheet已被弃用,取而代之的是UIAlertController,这需要在最顶部的视图控制器上显示。

UIViewController+TopMostViewController.h

#import <UIKit/UIKit.h>
@interface UIViewController (TopMostViewController)
- (UIViewController *)topMostViewController;
@end
@interface UIApplication (TopMostViewController)
- (UIViewController *)topMostViewController;
@end

UIViewController+TopMostViewController.m

#import "UIViewController+TopMostViewController.h"
@implementation UIViewController (TopMostViewController)
- (UIViewController *)topMostViewController
{
    if (self.presentedViewController == nil)
    {
        return self;
    }
    else if ([self.presentedViewController isKindOfClass:[UINavigationController class]])
    {
        UINavigationController *navigationController = (UINavigationController *)self.presentedViewController;
        UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
        return [lastViewController topMostViewController];
    }
    UIViewController *presentedViewController = (UIViewController *)self.presentedViewController;
    return [presentedViewController topMostViewController];
}
@end
#pragma mark -
@implementation UIApplication (TopMostViewController)
- (UIViewController *)topMostViewController
{
    return [self.keyWindow.rootViewController topMostViewController];
}
@end

我建议你使用NSNofiticationCenter。

//in AppDelegate:
@interface AppDelegate()
{
    ...
    id lastViewController;
    ...
}
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ...
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleCurrentViewController) name:@"CurrentViewController" object:nil];
    ...
}
- (void)handleCurrentViewController:(NSNotification *)notification {
    if([[notification userInfo] objectForKey:@"lastViewController"]) {
        lastViewController = [[notification userInfo] objectForKey:@"lastViewController"];
    }
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{    
    NSLog(@"last view controller is %@", [(UIViewController *)lastViewController class]);
}
@end
//in every ViewController you want to detect
@implementation SomeViewController
...
- (void) viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"CurrentViewController" object:nil userInfo:[NSDictionary dictionaryWithObjectsAndKeys:self, @"lastViewController", nil]];
}
...
@end

Swift 中的出色解决方案,在 AppDelegate 中实现

func getTopViewController()->UIViewController{
    return topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
}
func topViewControllerWithRootViewController(rootViewController:UIViewController)->UIViewController{
    if rootViewController is UITabBarController{
        let tabBarController = rootViewController as! UITabBarController
        return topViewControllerWithRootViewController(tabBarController.selectedViewController!)
    }
    if rootViewController is UINavigationController{
        let navBarController = rootViewController as! UINavigationController
        return topViewControllerWithRootViewController(navBarController.visibleViewController)
    }
    if let presentedViewController = rootViewController.presentedViewController {
        return topViewControllerWithRootViewController(presentedViewController)
    }
    return rootViewController
}

目标 - C

- (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;
    }
}
这对

我有用。我有很多目标有不同的控制器,所以以前的答案似乎不起作用。

首先,您希望在 AppDelegate 类中实现此内容:

var window: UIWindow?

然后,在您的函数中

let navigationController = window?.rootViewController as? UINavigationController
if let activeController = navigationController!.visibleViewController {
    if activeController.isKindOfClass( MyViewController )  {
        println("I have found my controller!")    
   }
}

您可以尝试通过以下方式获取最顶层的视图

[[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];

尽管此视图可能不可见,甚至被其某些子视图所覆盖......

这取决于您的 UI,但可能会有所帮助。

如果在应用委托中有导航控制器,只需使用 visibleViewController 属性。它会给你可见的控制器,即使它是一个模态。

在 swift 中,你可以像这样获得活动的 ViewController:

 let navigationController = application.windows[0].rootViewController as UINavigationController
 let activeViewCont = navigationController.visibleViewController

上述其他解决方案仅部分工作,因为无法处理复杂的视图层次结构(集成在选项卡栏控制器中的导航控制器、拆分视图控制器、视图容器以及警报控制器可能会搞砸事情(。

我通过在当前视图控制器的引用

中保留对当前视图控制器的引用来解决此问题 应用委托。每次视图出现时,我都会利用 viewDidAppear(animated:)并在应用委托中设置引用。

我知道问题是关于 Objective-C 的,但我只能提供 Swift 代码,我相信它对这两种类型的用户都很有用。

首先:我已经实现了一个协议来保持事物的清洁和可重用:

protocol UpdatableViewController {
    func updateUI()
}

第二:我添加了对 AppDelegate 的引用:

var currentViewController: UpdatableViewController?

第三:我在viewDidAppear((:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate
    appDelegate?.currentViewController = self
}

第四:

extension ViewController1: UpdatableViewController {
    func updateUI() {
        print("Implement updating here")
    }
}

最好的解决方案,也适用于UITabBarController中的moreNavigationController

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
    }
}

下面的代码运行良好。

+(UIViewController*( findBestViewController:(UIViewController*(vc {

if (vc.presentedViewController) {
    // Return presented view controller
    return [AppDelegate findBestViewController:vc.presentedViewController];
} else if ([vc isKindOfClass:[UISplitViewController class]]) {
    // Return right hand side
    UISplitViewController* svc = (UISplitViewController*) vc;
    if (svc.viewControllers.count > 0)
        return [AppDelegate findBestViewController:svc.viewControllers.lastObject];
    else
        return vc;
} else if ([vc isKindOfClass:[UINavigationController class]]) {
    // Return top view
    UINavigationController* svc = (UINavigationController*) vc;
    if (svc.viewControllers.count > 0)
        return [AppDelegate findBestViewController:svc.topViewController];
    else
        return vc;
} else if ([vc isKindOfClass:[UITabBarController class]]) {
    // Return visible view
    UITabBarController* svc = (UITabBarController*) vc;
    if (svc.viewControllers.count > 0)
        return [AppDelegate findBestViewController:svc.selectedViewController];
    else
        return vc;
} else {
    // Unknown view controller type, return last child view controller
    return vc;
}

}

+(UIViewController*( currentViewController {

// Find best view controller
UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
return [AppDelegate findBestViewController:viewController];

}

最新更新