iOS學習——獲取當前最頂層的ViewController


  在iOS開發過程中,我們經常性會需要獲取當前頁面的ViewController,然后利用ViewController進行一些操作,例如在最頂層的ViewController上展示一個UIAlertController,或者在最頂層的ViewController上present另一個ViewController,或者進行其他操作。

1 實現思路

  通過最底層的ViewController依次向上尋找,直到找到最頂層的ViewController,也就是從UIApplication的keyWindow的rootViewController開始尋找(如果有多個UIWindow則要考慮UIWindow的選擇問題。

  在尋找的過程中,要分別考慮當前ViewController是UITabBarController和UINavigationController的情況,同時還要考慮到當前ViewController是否通過 presentViewController:animated:completion: 模態展示了其他ViewController。

2 實現方法

方法一:

- (UIViewController *)topViewController {
    UIViewController *resultVC;
    resultVC = [self _topViewController:[[UIApplication sharedApplication].keyWindow rootViewController]];
    while (resultVC.presentedViewController) {
        resultVC = [self _topViewController:resultVC.presentedViewController];
    }
    return resultVC;
}

- (UIViewController *)_topViewController:(UIViewController *)vc {
    if ([vc isKindOfClass:[UINavigationController class]]) {
        return [self _topViewController:[(UINavigationController *)vc topViewController]];
    } else if ([vc isKindOfClass:[UITabBarController class]]) {
        return [self _topViewController:[(UITabBarController *)vc selectedViewController]];
    } else {
        return vc;
    }
    return nil;
}

使用方法:

UIViewController *topmostVC = [self topViewController];

方法二:

//獲取當前屏幕顯示的viewcontroller
- (UIViewController *)getCurrentVC
{
    UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
    
    UIViewController *currentVC = [self getCurrentVCFrom:rootViewController];
    
    return currentVC;
}

- (UIViewController *)getCurrentVCFrom:(UIViewController *)rootVC
{
    UIViewController *currentVC;
    
    if ([rootVC presentedViewController]) {
        // 視圖是被presented出來的
        rootVC = [rootVC presentedViewController];
    }

    if ([rootVC isKindOfClass:[UITabBarController class]]) {
        // 根視圖為UITabBarController
        currentVC = [self getCurrentVCFrom:[(UITabBarController *)rootVC selectedViewController]];  
    } else if ([rootVC isKindOfClass:[UINavigationController class]]){
        // 根視圖為UINavigationController
        currentVC = [self getCurrentVCFrom:[(UINavigationController *)rootVC visibleViewController]];  
    } else {
        // 根視圖為非導航類 
        currentVC = rootVC;
    }
    
    return currentVC;
}
  解析代碼主要使用了遞歸的思想(哈哈哈,畢業工作半年,發覺第一次寫iOS用到遞歸,突然覺得高大上)。
[UIApplication sharedApplication].keyWindow.rootViewController獲取到的是項目的根視圖,結合可能用到UITabBarController或者UINavigationController作為導航結構,以及可能present出新的VC,其實如果用storyboard的方式寫UI的話就很清晰,類似樹的結構,再利用遞歸找到當前視圖。
  ps:  
  如果是需要push新的視圖,就非常簡單了。用上面的方法獲取到頂層的視圖,判斷currentVC.navigationController是否為nil。(為nil,則新建UINavigationController,然后再push;否則直接用currentVC.navigationController去push)。

三 擴展

  如果用到的場景主要是vc里,可以弄成類別如下:

#import "UIViewController+Helper.h"

@property (nonatomic, strong ,readonly) UIViewController * _Nullable currentVC;

//當前屏幕顯示的viewcontroller
-(UIViewController *)currentVC{
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
UIViewController *controller = [self getCurrentVCFrom:rootViewController];
return controller;
}
//getCurrentVCFrom參考上文兩種方法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM