美文网首页swift编程开发swift-问题栈Window
iOS 获取当前显示的ViewController

iOS 获取当前显示的ViewController

作者: 朱_源浩 | 来源:发表于2016-08-31 19:43 被阅读13928次

    我们在非视图类中想要随时展示一个view时,需要将被展示的view加到当前view的子视图,或需要 presentViewController,或pushViewContrller,这些操作都需要获取当前正在显示的ViewController。

    发觉百度搜出来好多不科学的方法,有时候还是自己动脑子想好。。。
    下面提供了一个公用的方法去获取当前ViewController,也建议直接改成静态方法,放到工具类里直接调用更加科学。

    具体代码如下:

    //获取当前屏幕显示的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)

    ps2:
    补充评论里好的建议,如果用到的场景主要是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参考上文
    

    还有什么不懂的就留言问问哈。。。。

    相关文章

      网友评论

      • Hunter琼:这个过去当前视图控制器方法 有时候没用 比如侧滑(抽屉)效果App root是控制器 控制器上一个左控制器和一个右TabbarVC 是获取不到Tab的控制器的 只能用黑魔法来获取
        朱_源浩:@Hunter琼 哈哈哈的确是,得具体情况调整
      • 红红火火恍恍惚惚哼哼哈哈黑乎乎:优秀,学习了,思路非常清晰
      • 唐扬生:不错,解决了我的问题
      • 89848af90932:可以完善一下,如果tabbarVc或者navigationVc里面有subViewController的情况
      • 74a6fed0ebe3:if ([rootVC presentedViewController]) {
        // 视图是被presented出来的

        rootVC = [rootVC presentedViewController];
        }
        这里应改为if ([rootVC presentedViewController]) {
        // 视图是被presented出来的

        return [self getCurrentVCFrom:rootvc. presentedViewController];
        }
        否则不能获取到多次present的vc
        游龙飞雪:这里文中是没问题的呀~~
      • a7c6cec64788:大神 你好 我是在view里面调用的 push到VC里面 但是 push之后 点击返回返回不了了
        a7c6cec64788:@朱_源浩 谢谢 大神 是我自己这边的问题
        朱_源浩:返回不了?是navigationcontroller吗,,得看返回是dismiss还是pop
      • SoaringHeart:不错,感觉是目前最完美的方法,可以更近一步改为属性
        建一个控制器类别
        #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;
        }
        SoaringHeart:我封装方法的思路是能类别就不封装成工具
        朱_源浩:可以呀,感觉也是个思路
        也有另外用的场景,所以没弄成类别,我经常用于工具类或者appdelegate里。:+1:
      • 朱晓晓的技术博客:请问可以转载您的文章吗?谢谢
        朱晓晓的技术博客:@朱_源浩 谢谢
        朱_源浩:@朱晓晓的技术博客 可以呀,注释下小的出处,欢迎转载:blush:
      • 崠崠:如果是想得到viewController是最后一个presented出来的childViewController 这种情况下,貌似获取不到,只能到父容器这里
        朱_源浩:应该是可以的,下面代码有拿presentedViewController。。
        if ([rootVC presentedViewController]) {
        // 视图是被presented出来的
        rootVC = [rootVC presentedViewController];
        }

        不过如果是要拿vc里的childViewController,应该支持不到,建议自己在方法里面做对应修改去获取。
      • xiao彰:我这边是用Aspects 截取到系统的所有UIViewController 的viewWillAppear的方法 然后写个单例记录一下就好了
        xiao彰:@不会算卦的杨大仙 本来不走viewwillappear不就是坑么:sweat:
        不会算卦的杨大仙:@xiao彰 你这种解决方法有坑的 自定义modal转场如果是custom的话 是不会走viewWillAppear方法的
        xiao彰:不想用第三方的话也可以直接用runtime替换系统的viewWillAppear方法,然后记录一下
      • 超_iOS:if ([rootVC presentedViewController]) {
        // 视图是被presented出来的

        rootVC = [rootVC presentedViewController];
        }楼主这个没太明白.望解释下
        游龙飞雪:@_超 if条件的意思是,如果rootVc已经present出另一个不为nil的vc了,那就走到if内部,然后获取到这个被present出来的vc,然后重新赋值给rootVc;然后继续往下走,会走到文中最后一个分值,直接返回了这个被prensent出来的vc。
        这种方法挺好,如果要获取一个显示的vc的childViewController的话,还需要自己加代码。但如果这个vc有多个childVcs,那恐怕要分别给childVc加标记了,才能获取到精确的VC。
        超_iOS:是找到最初present的那个VC吧?我这算自问自答吧
      • Azen:不如试试window呀,就不用关心当前展示的是啥了
        sclcoder:@朱_源浩 我也是想刷新当前的Vc 才来找的代码:smile:
        朱_源浩:@Azen 我是有一个统一处理的方法,需要刷新当前vc,所以就需要获取到准确的vc哈。
      • 摆渡人不渡人:通过响应链获取是不是好一些。
        游龙飞雪:这种方法挺棒,赞一个!
        如果要获取一个显示的vc的childViewController的话,还需要自己加代码。但如果这个vc有多个childVcs,那恐怕要分别给childVc加标记了,才能获取到精确的VC。
        朱_源浩:@摆渡人不渡人 具体是怎样 :no_mouth: 。。。我看过别人写的,会不会只获取到外层的

      本文标题:iOS 获取当前显示的ViewController

      本文链接:https://www.haomeiwen.com/subject/dgtcettx.html