在iOS 6中,隱藏Status Bar非常的簡單。
// iOS 6及以前,隱藏狀態欄 [[UIApplication sharedApplication] setStatusBarHidden:YES];
來到了iOS 7的年代以後,需要在UIViewController中指定:
#ifdef __IPHONE_7_0
- (BOOL)prefersStatusBarHidden {
return YES;
}
#endifif ([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