zoukankan      html  css  js  c++  java
  • iOS 使用Method Swizzling隐藏Status Bar

    在iOS 6中,隐藏Status Bar很的简单。

    // iOS 6及曾经,隐藏状态栏
    [[UIApplication sharedApplication] setStatusBarHidden:YES];


    来到了iOS 7的年代以后,须要在UIViewController中指定:

    #ifdef __IPHONE_7_0
    - (BOOL)prefersStatusBarHidden {
        return YES;
    }
    #endif

    并通过下列代码刷新状态栏:

    if ([viewController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
            [viewController prefersStatusBarHidden];
            [viewController performSelector:@selector(setNeedsStatusBarAppearanceUpdate)];
    }


    可是上述代码并非万能的,iOS 7的某些场合还是会造成无法隐藏Status Bar的问题。

    在ParentViewController中Add一个ChildViewController,假设ParentViewController的

    prefersStatusBarHidden方法返回的是NO,那么即使ChildViewController中的prefersStatusBarHidden方法返回的是YES并调用以上代码。也无法隐藏Status Bar。


    解决方式:Method Swizzling

    在ChildViewController中Hook ParentViewController的prefersStatusBarHidden方法,使其返回YES,然后调用更新状态栏的代码,实现隐藏状态栏。须要注意的是。在适当场合,比如ChildViewController的viewWillDisappear方法中。须要将Hook的方法还原。否则可能造成奇怪的情况出现。


    代码例如以下:

    1.在ChildViewController的viewDidLoad方法中替换ParentViewController的prefersStatusBarHidden方法的实现

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        _statusBarHidden = [UIApplication sharedApplication].statusBarHidden;
        // 进入界面时隐藏状态栏
        UIViewController *parentViewController = self.parentViewController;
        if ([parentViewController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
            [self hookPrefersStatusBarHidden:parentViewController];
        }
        else {
            // iOS 6及曾经,隐藏状态栏
            [[UIApplication sharedApplication] setStatusBarHidden:YES];
        }
    }

    2.使用Runtime的Method Swizzling大法替换ChildViewController和ParentViewController两者的prefersStatusBarHidden方法的实现

    - (void)hookPrefersStatusBarHidden:(UIViewController *)parentViewController {
        /**
         Method Swizzling
         
         1.假设ParentViewController的prefersStatusBarHidden返回NO。那么Add在其上的ChildViewController的prefersStatusBarHidden即使返回YES,也无法隐藏状态栏。因此在viewDidLoad时。须要将ParentViewController中prefersStatusBarHidden方法的实现替换掉
         2.在viewWillDisappear时。须要将交换的方法实现还原回来
         */
        Method src_method = class_getInstanceMethod([UIViewController class], @selector(prefersStatusBarHidden));
        Method des_method = class_getInstanceMethod([self class], @selector(hook_prefersStatusBarHidden));
        method_exchangeImplementations(src_method, des_method);
        
        // 刷新状态栏
        dispatch_async(dispatch_get_main_queue(), ^{
            [parentViewController prefersStatusBarHidden];
            [parentViewController performSelector:@selector(setNeedsStatusBarAppearanceUpdate)];
        });
    }
    
    - (BOOL)hook_prefersStatusBarHidden {
        // 隐藏状态栏
        return YES;
    }

    3.在ChildViewController从ParentViewController中移除时。viewWillDisappear方法必然会被调用(注意不要在viewDidDisappear方法中调用,此时ChildViewController可能已经被释放掉),因此能够在该方法中还原两者的prefersStatusBarHidden的实现

    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        
        // 退出界面时。还原状态栏的初始状态
        UIViewController *parentViewController = self.parentViewController;
        if ([parentViewController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
            [self hookPrefersStatusBarHidden:parentViewController];
        }
        else {
            // iOS 6及曾经,恢复状态栏的初始状态
            [[UIApplication sharedApplication] setStatusBarHidden:_statusBarHidden];
        }
    }


    有时候为了确保状态栏隐藏。能够强制运行以上代码。

    在实际project中第二次用上Runtime的特性。实在开心,哈哈。


    參考资料:

    iOS7 隐藏状态栏 (电池栏)

    Objective-C的hook方案(一): Method Swizzling



  • 相关阅读:
    编程总结2
    编程总结3
    《秋季学期学习总结》
    《人生路上对我影响最大的三位老师》
    第八周编程总结
    第七周编程总结
    第六周编程总结
    第五周作业
    第四周编程总结
    第三周编程总结
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5144739.html
Copyright © 2011-2022 走看看