アプリデリゲートから現在のViewControllerを取得するには、アプリ用に設定したnavigationController
プロパティを使用できることを知っています。ただし、アプリ全体の多くの場所で、モーダルナビゲーションコントローラーが表示されている可能性があります。現在のナビゲーションコントローラーは、アプリデリゲートが参照を保持しているものとは異なるため、アプリデリゲートからこれを検出する方法はありますか?
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
要点 に基づいて、[[UIApplication sharedApplication] topMostViewController]
を呼び出すと、アプリで最上位のView Controllerが得られるように、最上位のViewControllerを取得するためのカテゴリを作成しました。
これは、UIAlertView
とUIActionSheet
が廃止されてUIAlertController
が廃止されたiOS8で特に役立ちます。これは、最上位のViewControllerに表示する必要があります。
#import <UIKit/UIKit.h>
@interface UIViewController (TopMostViewController)
- (UIViewController *)topMostViewController;
@end
@interface UIApplication (TopMostViewController)
- (UIViewController *)topMostViewController;
@end
#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
これは私のために働いた。コントローラーが異なるターゲットがたくさんあるので、以前の回答はうまくいかなかったようです。
まず、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!")
}
}
次のようにして、トップを取得してみてくださいview
[[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
このビューは見えないか、サブビューの一部で覆われている可能性がありますが...
UIによって異なりますが、役立つ場合があります。
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;
}
}
App Delegateにナビゲーションコントローラーがある場合は、 visibleViewController プロパティを使用するだけです。モーダルであっても、目に見えるコントローラーが表示されます。
Swiftでは、次のようにアクティブなViewControllerを取得できます:
let navigationController = application.windows[0].rootViewController as UINavigationController
let activeViewCont = navigationController.visibleViewController
以下のコードは非常にうまく機能します。
+(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];
}
最良の解決策は、moreNavigationController
のUITabBarController
でも機能します。
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
}
}
上記の他のソリューションは、複雑なビュー階層が処理されないため、部分的にしか機能しません(タブバーコントローラーに統合されたナビゲーションコントローラー、分割ビューコントローラー、ビューコンテナー、およびアラートコントローラーが混乱する可能性があります)。
AppDelegateに現在のViewControllerの参照を保持することで、これを解決します。ビューが表示されるたびに、
viewDidAppear(animated:)
を利用して、アプリデリゲートで参照を設定します。
質問がObjective-Cに関するものであることは知っていますが、提供できるのはSwiftコードのみであり、両方のタイプのユーザーに役立つと確信しています。
最初に:私は物事を清潔で再利用可能に保つためのプロトコルを実装しました:
protocol UpdatableViewController {
func updateUI()
}
2番目:AppDelegateへの参照を追加しました:
var currentViewController: UpdatableViewController?
3番目:viewDidAppear()で現在のViewControllerを設定します。
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate
appDelegate?.currentViewController = self
}
第4:
extension ViewController1: UpdatableViewController {
func updateUI() {
print("Implement updating here")
}
}