大家都知道,UINavigationController對(duì)象有一個(gè)方法pushViewController,用來做視圖跳轉(zhuǎn),也是在iOS開發(fā)中常用的頁面轉(zhuǎn)換方法之一。大多數(shù)APP的結(jié)構(gòu)一般都是,使用一個(gè)UITabBarController,每個(gè)tab上都是一個(gè)UINavigationController,然后各個(gè)tab上的navigationController自己管理各自的視圖棧。

這個(gè)時(shí)候,如果此時(shí)APP想要push一個(gè)新的VC,一般是在某個(gè)VC上調(diào)用:
[self.navigationController pushViewController:newVC animated:YES];
那問題來了,產(chǎn)品比較任性,如果有一個(gè)需求,就是要求做一個(gè)跳轉(zhuǎn)工具,要求要能在任何地方(包括非VC中),都能在當(dāng)前頁面push新的VC,那又該怎么做呢?

如果能拿到UITabBarController的對(duì)象,例如放在了delegate中(這里設(shè)想AppDelegateInstance就是delegate的對(duì)象,而UITabBarController的成員變量名為tabBar),也可以使用
[AppDelegateInstance.tabBar.selectedViewController pushViewController:newVC animated:YES];
好像能隨時(shí)push新VC了......
不對(duì)!狀況又來了,如果在當(dāng)前VC上可能又present出一個(gè)頁面,即present出一個(gè)新的NAV,這時(shí)候:

這個(gè)時(shí)候,有可能AppDelegateInstance.tabBar.selectedViewController就不是當(dāng)前的NAV了,自然就不能正確push了。
那怎么辦呢?

如果能拿到當(dāng)前正在顯示的NAV就好辦多了,那樣我直接拿這個(gè)NAV就可以push任何頁面了。
思路:
1.當(dāng)前顯示的肯定有一個(gè)window包含了所有視圖控制器、導(dǎo)航控制器;
2.視圖控制器、導(dǎo)航控制器出現(xiàn)的方式只有3中:tabBar selected、push、present;
3.從“1”的window出發(fā),找到每一層顯示中的NAV或者VC,直到找到最后一層,就是當(dāng)前顯示的VC,就能拿到當(dāng)前的NAV了。
這里我創(chuàng)建了一個(gè)分類UIApplication+Visible,獲取APP的主window,再遞歸進(jìn)行當(dāng)前顯示中VC、NAV的查詢:
#import "UIApplication+Visible.h"
@implementation UIApplication (Visible)
- (UIWindow *)mainWindow {
return self.delegate.window;
}
- (UIViewController *)visibleViewController {
UIViewController *rootViewController = [self.mainWindow rootViewController];
return [self getVisibleViewControllerFrom:rootViewController];
}
- (UIViewController *) getVisibleViewControllerFrom:(UIViewController *) vc {
if ([vc isKindOfClass:[UINavigationController class]]) {
return [self getVisibleViewControllerFrom:[((UINavigationController *) vc) visibleViewController]];
} else if ([vc isKindOfClass:[UITabBarController class]]) {
return [self getVisibleViewControllerFrom:[((UITabBarController *) vc) selectedViewController]];
} else {
if (vc.presentedViewController) {
return [self getVisibleViewControllerFrom:vc.presentedViewController];
} else {
return vc;
}
}
}
- (UINavigationController *)visibleNavigationController {
return [[self visibleViewController] navigationController];
}
@end
然后你就這樣調(diào)用
UINavigationController *nav = [[UIApplication sharedApplication] visibleNavigationController];
[nav pushViewController:newVC animated:YES];
成功啦?。?!

最后,可能有些人要疑惑,為什么mainWindow方法中要使用delegate.window而不使用[UIApplication sharedApplication].keyWindow呢?
因?yàn)閗eyWindow并不是一直都是APP的主界面的window,例如使用了UIAlertView,keyWindow就會(huì)變成alertView的window,這時(shí)候我們的輪子就不能跑了。
好了,可能有些地方寫得比較模糊、或者有缺陷,歡迎指出。
