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