iOS 使用Method Swizzling隱藏Status Bar

來源:互聯網
上載者:User

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];    }}


有時候為了確保狀態列隱藏,可以強制執行以上代碼。

在實際工程中第二次用上Runtime的特性,實在開心,哈哈。


參考資料:

iOS7 隱藏狀態列 (電池欄)

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



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.