iOS 7 ~iOS 9
從iOS 7開始系統風格大變樣,圖示扁平了,狀态欄也不在鬧獨立了。因為狀态欄的會受到導航欄或者View背景色的影響,是以狀态欄的風格也需要實時調整了。
想要改變狀态欄的樣式,想要控制狀态欄的顯示與隐藏,該怎麼做呢?
1. 用UIApplication的API
首先,需要在plist檔案裡将【View controller-based status bar appearance】設定為NO,因為它的預設值是YES,然後就可以利用UIApplication 來設定了。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CM1UzMzYmMlVGZmNGZ4Y2YyYzXzIDMzETM0EzLcdDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
plist設定
先上效果動畫:
再上源碼:
- (IBAction)changeStatus:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 0) {
// [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
// 帶動畫效果,動畫效果其實就是變換的時間變慢了
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
} else {
// [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
// 帶動畫效果,動畫效果其實就是變換的時間變慢了
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
}
}
- (IBAction)showOrHidden:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 0) {
// 第二個參數是個枚舉類型
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
// 不帶動畫效果
// [[UIApplication sharedApplication] setStatusBarHidden:NO];
} else {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
// 不帶動畫效果
// [[UIApplication sharedApplication] setStatusBarHidden:YES];
}
}
2. 重寫ViewController方法
首先,要確定plist檔案中【View controller-based status bar appearance】為YES,沒有添加這個key的時候,預設是YES。
plist設定
然後在視圖控制器中,重寫如下三個方法即可:
要重寫的方法
因為這三個方法都有預設值,如果我們要的狀體欄樣式什麼的跟預設值效果一緻,則不需要重寫;如果不想要預設的效果,則直接在這三個方法裡return 相應的值即可。你不必三個方法都重寫,看實際情況。例如,我想要在這個界面時狀态欄為白色,狀态欄不隐藏,那麼我隻用重寫-preferredStatusBarStyle,like this:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
因為我這裡需要做一個切換是以,我首先定義了兩個property:
@property (assign, nonatomic) UIStatusBarStyle statusBarStyle; /**< 狀态欄樣式 */
@property (assign, nonatomic) BOOL statusBarHidden; /**< 狀态欄隐藏 */
然後改變UISegmentedControl的值時,在響應的Action方法裡改變上述property的值,再調用
-setNeedsStatusBarAppearanceUpdate即可。
示例代碼:
#pragma mark - ViewController方式
- (IBAction)changeStyle:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 0) {
_statusBarStyle = UIStatusBarStyleDefault;
} else {
_statusBarStyle = UIStatusBarStyleLightContent;
}
[self setNeedsStatusBarAppearanceUpdate];
}
- (IBAction)statusShowOrHidden:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 0) {
_statusBarHidden = NO;
} else {
_statusBarHidden = YES;
}
[self setNeedsStatusBarAppearanceUpdate];
}
#pragma mark - 需要重寫的幾個狀态欄方法
/**
* 控制狀态欄的樣式
* 要重新整理狀态欄,讓其重新執行該方法需要調用{-setNeedsStatusBarAppearanceUpdate}
*
* @return 将要顯示的狀态欄樣式
*/
- (UIStatusBarStyle)preferredStatusBarStyle
{
return _statusBarStyle;
}
/**
* 狀态欄顯示還是隐藏
* 要重新整理狀态欄,讓其重新執行該方法需要調用{-setNeedsStatusBarAppearanceUpdate}
*
* @return BOOL值
*/
- (BOOL)prefersStatusBarHidden
{
return _statusBarHidden;
}
/**
* 狀态欄改變的動畫,這個動畫隻影響狀态欄的顯示和隐藏
*
* @return 動畫效果
*/
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation
{
return UIStatusBarAnimationSlide;
}
iOS 9 之後
如上面第二張圖所示,UIApplication的控制狀态欄的方法,在iOS 9之後被棄用了。
是以iOS 9之後盡量使用重寫ViewController方法的方式吧。
注意點
- 情形一
如果我們使用UINavigationController,會發現在原來的ViewController裡修改狀态欄的style不起作用了,但是控制狀态欄的顯示和隐藏依然OK。但是使用UITabBarController依然正常,狀态欄不受UITabBarController影響。
重寫UINavigationController的三個方法:
- (UIStatusBarStyle)preferredStatusBarStyle
{
NSLog(@"導航欄-%s",__func__);
return [self.topViewController preferredStatusBarStyle];
}
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation
{
NSLog(@"導航欄-%s",__func__);
return UIStatusBarAnimationNone;
}
- (BOOL)prefersStatusBarHidden
{
NSLog(@"導航欄-%s",__func__);
return NO;
}
從列印結果:
2016-05-18 13:18:10.248 PractiseProject[3296:112707] 導航欄--[BaseNavigationController preferredStatusBarStyle]
2016-05-18 13:18:10.249 PractiseProject[3296:112707] -[ViewController prefersStatusBarHidden]
2016-05-18 13:18:10.275 PractiseProject[3296:112707] 導航欄--[BaseNavigationController preferredStatusBarStyle]
2016-05-18 13:18:10.275 PractiseProject[3296:112707] -[ViewController prefersStatusBarHidden]
2016-05-18 13:18:10.275 PractiseProject[3296:112707] 導航欄--[BaseNavigationController preferredStatusBarStyle]
2016-05-18 13:18:10.276 PractiseProject[3296:112707] -[ViewController prefersStatusBarHidden]
可以看出,隻調用了第一個方法。是以我們隻需要重寫UINavigaitonController的- preferredStatusBarStyle即可。
- 情形二
狀态欄的樣式、是否顯示實際上是由頂層window的目前視圖控制器決定的。
比如我們在程式入口處建立一個新的window:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.statusWindow = [[UIWindow alloc] initWithFrame:application.statusBarFrame];
// 這裡設定windowLevel 為UIWindowLevelStatusBar或者UIWindowLevelAlert都可以
self.statusWindow.windowLevel = UIWindowLevelStatusBar;
// 顔色必須為clearColor,否則會蓋住狀态欄的區域
self.statusWindow.backgroundColor = [UIColor clearColor];
self.statusWindow.rootViewController = [[StatusViewContrller alloc] init];
self.statusWindow.hidden = NO;
return YES;
}
然後在StatusViewContrller中重寫如下方法:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
// 如果想要顯示狀态欄,必須重寫這個方法,并return NO
- (BOOL)prefersStatusBarHidden
{
return NO;
}
這樣最終狀态欄的樣式就由StatusViewContrller決定了,而不是由原來的ViewController決定了。
建立頂層window之後,修改狀态欄的樣式就不友善了。
為了解決這個問題,我們可以将StatusViewContrller弄成單例,然後定義兩個property來控制樣式和是否隐藏即可。
#import
@interface StatusViewContrller : UIViewController
@property (assign, nonatomic) UIStatusBarStyle statusBarStyle; /**< 狀态欄樣式 */
@property (assign, nonatomic) BOOL statusBarHidden; /**< 狀态欄隐藏 */
+ (instancetype)sharedInstance;
@end
// 建立單例的關鍵代碼
static id instance = nil;
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
// 這個方法是關鍵
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [super allocWithZone:zone];
});
return instance;
}
// 重寫的方法
- (UIStatusBarStyle)preferredStatusBarStyle
{
return _statusBarStyle;
}
- (BOOL)prefersStatusBarHidden
{
return _statusBarHidden;
}
// setter
- (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle
{
_statusBarStyle = statusBarStyle;
[self setNeedsStatusBarAppearanceUpdate];
}
- (void)setStatusBarHidden:(BOOL)statusBarHidden
{
_statusBarHidden = statusBarHidden;
[self setNeedsStatusBarAppearanceUpdate];
}