你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS 使用Method Swizzling隱藏Status Bar

iOS 使用Method Swizzling隱藏Status Bar

編輯:IOS開發綜合

在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



  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved