目錄
先插入以下介紹以下本編文章除標題所講知識外,還額外包含的內(nèi)容有如下:
1、獲取當前顯示的視圖控制器ViewController
2、如何在多次presentViewController后直接返回到指定層
3、presentedViewController 與 presentingViewController
4、如何通過視圖(view)獲取該視圖所在的控制器(viewController)
一、前言:
本來不怎么想寫這篇文章的, 因為這種東西網(wǎng)上隨便搜一大堆。但是還是發(fā)現(xiàn)項目中有些同學(xué),沒怎么理解好,直接照搬網(wǎng)上的,殊不知其本身雖處理了大部分情況,卻仍有一些情況是漏掉的。所以就有了下面這篇文章。
二、場景:
在處理 URL Router 跳轉(zhuǎn)的時候,經(jīng)常需要得到“當前最上層的視圖控制器”來進行視圖跳轉(zhuǎn)。
三、注意點:
網(wǎng)上比較多遺漏的場景是:A present B, B present C,在A中查找當前顯示的視圖控制器的情況。
四、直接快速使用方法:
使用方法很簡單:
①、Podfile添加pod 'CJBaseHelper/UIViewControllerCJHelper',并pod update或pod install
②、庫引入成功后,直接使用如下方法即可。即:
UIViewController *vc = [UIViewControllerCJHelper findCurrentShowingViewController];
或
UIViewController *vc = [UIViewControllerCJHelper findCurrentShowingViewControllerFrom:self];
至此,恭喜你大功告成?。?!

如果您還不清楚,可詳細查看以下說明。如果已清楚及不想了解原理,請?zhí)亮榭雌渌麅?nèi)容
詳細的使用方法及原理介紹如下:
1、查看開源庫CJBaseHelper內(nèi)容,可略過
獲取方法已整理到開源庫CJBaseHelper中的UIViewControllerCJHelper。該開源庫內(nèi)容,可通過pod search CJBaseHelper查看,查看結(jié)果如下:
CJBaseHelper/UIViewControllerCJHelper.png
如果你在終端執(zhí)行pod search CJBaseHelper,未得到上面的結(jié)果,是因為cocoaPods的本地search_index.json文件有問題,
方法①:請前往~/Library/Caches/CocoaPods/search_index.json將該文件刪除,
方法②:或者直接在終端輸入:rm ~/Library/Caches/CocoaPods/search_index.json,
刪除后,再重新執(zhí)行命令即可。
2、Podfile添加pod 'CJBaseHelper/UIViewControllerCJHelper'后,執(zhí)行pod install即可使用該庫中的UIViewControllerCJHelper,即。
platform :ios, '8.0'
inhibit_all_warnings!
target 'CJDemo' do
pod 'CJBaseHelper', :subspecs => ['UIViewControllerCJHelper']
end
target 'CJDemoTests' do
end
即通過調(diào)用以下兩個方法中的任意一個即可獲取到當前顯示的視圖控制器。
///獲取Window當前顯示的視圖控制器ViewController
+ (UIViewController *)findCurrentShowingViewController;
/**
* 獲取Window當前顯示的視圖控制器ViewController
*
* @param vc 從哪個界面開始分析
*
* @return 當前顯示的視圖控制器ViewController
*/
+ (UIViewController *)findCurrentShowingViewControllerFrom:(UIViewController *)vc;
3、實際使用過程
//獲取Window當前顯示的視圖控制器ViewController方法①
UIViewController *currentShowViewController1 = [UIViewControllerCJHelper findCurrentShowingViewController];
NSLog(@"currentShowViewController1 = %@", NSStringFromClass([currentShowViewController1 class]));
//獲取Window當前顯示的視圖控制器ViewController方法②
UIViewController *currentShowViewController2 = [UIViewControllerCJHelper findCurrentShowingViewControllerFrom:self];
NSLog(@"currentShowViewController2 = %@", NSStringFromClass([currentShowViewController2 class]));
五、上述使用的CJBaseHelper/UIViewControllerCJHelper庫的代碼解析
代碼中包括兩種方法,一種是遍歷方法,一種是遞歸方法,兩種方法都能正確查找到當前正在顯示的視圖控制器。廢話不多說,直接上代碼。
+ (UIViewController *)findCurrentShowingViewController {
//獲得當前活動窗口的根視圖
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
UIViewController *currentShowingVC = [self findCurrentShowingViewControllerFrom:vc];
return currentShowingVC;
}
//注意考慮幾種特殊情況:①A present B, B present C,參數(shù)vc為A時候的情況
/* 完整的描述請參見文件頭部 */
+ (UIViewController *)findCurrentShowingViewControllerFrom:(UIViewController *)vc
{
//方法1:遞歸方法 Recursive method
UIViewController *currentShowingVC;
if ([vc presentedViewController]) { //注要優(yōu)先判斷vc是否有彈出其他視圖,如有則當前顯示的視圖肯定是在那上面
// 當前視圖是被presented出來的
UIViewController *nextRootVC = [vc presentedViewController];
currentShowingVC = [self findCurrentShowingViewControllerFrom:nextRootVC];
} else if ([vc isKindOfClass:[UITabBarController class]]) {
// 根視圖為UITabBarController
UIViewController *nextRootVC = [(UITabBarController *)vc selectedViewController];
currentShowingVC = [self findCurrentShowingViewControllerFrom:nextRootVC];
} else if ([vc isKindOfClass:[UINavigationController class]]){
// 根視圖為UINavigationController
UIViewController *nextRootVC = [(UINavigationController *)vc visibleViewController];
currentShowingVC = [self findCurrentShowingViewControllerFrom:nextRootVC];
} else {
// 根視圖為非導(dǎo)航類
currentShowingVC = vc;
}
return currentShowingVC;
/*
//方法2:遍歷方法
while (1)
{
if (vc.presentedViewController) {
vc = vc.presentedViewController;
} else if ([vc isKindOfClass:[UITabBarController class]]) {
vc = ((UITabBarController*)vc).selectedViewController;
} else if ([vc isKindOfClass:[UINavigationController class]]) {
vc = ((UINavigationController*)vc).visibleViewController;
//} else if (vc.childViewControllers.count > 0) {
// //如果是普通控制器,找childViewControllers最后一個
// vc = [vc.childViewControllers lastObject];
} else {
break;
}
}
return vc;
//*/
}

六、其他補充:
2、如何在多次presentViewController后直接返回到指定層
場景:如果多個控制器都通過 present 的方式跳轉(zhuǎn)呢?比如從A跳轉(zhuǎn)到B,從B跳轉(zhuǎn)到C,從C跳轉(zhuǎn)到D,如何由D直接返回到A呢?
答:可以通過 presentingViewController 一直找到A控制器,然后調(diào)用A控制器的 dismissViewControllerAnimated 方法。方法如下:
UIViewController *controller = self;
while(controller.presentingViewController != nil){
controller = controller.presentingViewController;
}
[controller dismissViewControllerAnimated:YES completion:nil];
PS:如果不是想直接返回到A控制器,比如想回到B控制器,while循環(huán)的終止條件可以通過控制器的類來判斷。
3、presentedViewController 與 presentingViewController
假設(shè)從A控制器通過present的方式跳轉(zhuǎn)到了B控制器,那么 A.presentedViewController 就是B控制器;
B.presentingViewController 就是A控制器。
4、如何通過視圖(view)獲取該視圖所在的控制器(viewController)
+ (nullable UIViewController *)findBelongViewControllerForView:(UIView *)view {
UIResponder *responder = view;
while ((responder = [responder nextResponder]))
if ([responder isKindOfClass: [UIViewController class]]) {
return (UIViewController *)responder;
}
return nil;
}
結(jié)束語:
如欲了解本文中更詳細內(nèi)容請點擊查看本文中所用開源庫CJBaseHelper中的UIViewControllerCJHelper。
=======================================================
其他更多好用的開源庫歡迎跳轉(zhuǎn)我的GitHub主頁,歡迎Watch/Star/Follow。
=======================================================
