聊一聊 iOS 状态栏

现在很多 APP 为了保持界面的统一,会让 iOS 状态栏的背景颜色和导航栏的颜色一致,有的时候还会隐藏状态栏,开发中修改状态栏往往一次弄好之后就不会再改变了,下面就记录一下各种调整状态栏颜色以及隐藏状态栏的设置(本文的内容只适用于 iOS7 及以上)

了解一下状态栏(UIStatusBar)

所谓状态栏就是我们的 iPhone 手机屏幕最顶端的20个像素高的那一部分,状态栏左边一般会有手机信号强度、运营商名字、Wi-Fi状态显示,中间会显示时间,状态栏右边会有定位显示、蓝牙显示已经电量显示

状态栏分两个部分:

  • 前景部分:就是上面说到的时间、电量等
  • 背景部分:就是状态栏背景

如图,上面的状态栏前景黑色,背景白色,下面的状态栏前景白色,背景黑色

设置 UIStatusBar 的前景部分

前景部分也就是时间、电量显示的这部分,有两种设置

  • UIStatusBarStyleDefault(默认的黑色)
  • UIStatusBarStyleLightContent(白色)

我们可以在 Info.plist 和代码里面设置这两种前景颜色样式

Info.plist 里面设置

Info.plist 里增加一个 Status bar style的键,这个键对应的值就是我们需要的 UIStatusBarStyleDefaultUIStatusBarStyleLightContent
另外还需要在 Info.plist 增加一个 View controller-based status bar appearance 的键并且值设置为 NO,这样 APP 启动之后前景的颜色样式就是 Info.plist 里面设置的风格了

代码里面设置

UIApplication 设置
1
2
3
4
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
//效果和上面的一样,增加了动画
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];

这种方法也需要在 Info.plist 增加一个 View controller-based status bar appearance 的键并且值设置为 NO

这里解释一下 View controller-based status bar appearance,这是官方文档的说明:

UIViewControllerBasedStatusBarAppearance (Boolean - iOS) Specifies whether the status bar appearance is based on the style preferred by the view controller that is currently under the status bar. When this key is not present or its value is set to YES, the view controller determines the status bar style. When the key is set to NO, view controllers (or the app) must each set the status bar style explicitly using the UIApplication object.

This key is supported in iOS 7.0 and later.

意思就是: 当该键不存在或其值设置为 YES 时,状态栏的样式由视图控制器决定(下面会讲到),当键设置为 NO 时,视图控制器(或应用程序)必须使用 UIApplication 对象显式地设置状态栏样式,这也解释了为什么上面的 Info.plistUIApplication 设置状态栏样式需要把这个键设置为 NO

UIViewController 里设置

上面使用 UIApplication 设置状态栏的样式的方法在 iOS9 已经被废弃了,苹果推荐使用 UIViewController- preferredStatusBarStyle 方法设置状态栏的样式,我们只需要在 UIViewController 里面重写 - preferredStatusBarStyle 方法,并返回需要的状态栏样式即可

1
2
3
4
- (UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}

这个方法需要注意:

  • 控制器在显示的时候就会立即调用这个方法,并根据这个方法设置状态栏的样式
  • 如果当前控制器已经显示出来了,你还希望可以改变当前的状态栏的样式,就需要用到另一个方法 - setNeedsStatusBarAppearanceUpdate,这个方法会通知系统去调用当前 UIViewController- preferredStatusBarStyle 方法,这样就可以重新设置当前控制器页面的状态栏样式了

但是实际使用中我们一般不会单独使用 ViewController 而是把 ViewController 加在 UINavigationController 里面使用,这个时候 ViewController 里面的 - preferredStatusBarStyle 方法并不会被调用,这个时候就需要用到 ViewController 的另一个方法 - childViewControllerForStatusBarStyle

如果是 ViewController 配合 UINavigationController 使用但是又希望状态栏的样式由当前的控制器决定,可以这样做:自定义一个继承自 UINavigationController 的子类,并且重写这个子类的 - childViewControllerForStatusBarStyle 方法:

1
2
3
4
- (UIViewController *)childViewControllerForStatusBarStyle{
return self.topViewController;
}

重写这个方法的意思就是,不调用当前 UINavigationController- preferredStatusBarStyle 方法,而是去调用navigationController.topViewControllerpreferredStatusBarStyle 方法,这样就能保证当前显示的UIViewControllerpreferredStatusBarStyle 可以决定状态栏的样式,除了重写子类的方法也可以使用分类的方法可以 参考这里

另外,有时我们当前显示的 UIViewController 可能添加了多个 childViewController,重写当前 UIViewControllerchildViewControllerForStatusBarStyle 方法,也可以使 childViewControllerpreferredStatusBarStyle 生效(当前 UIViewControllerpreferredStatusBarStyle 就不会被调用了)

总结起来就是:只要重写 UIViewControllerchildViewControllerForStatusBarStyle 方法返回值不是nil,那么这个 UIViewControllerpreferredStatusBarStyle 方法就不会被调用,而是会调用 childViewControllerForStatusBarStyle 这个方法返回的那个UIViewControllerpreferredStatusBarStyle 方法

设置 UIStatusBar 的背景部分

iOS7 以后默认情况下状态栏的背景为透明的,设置它的背景色有两种方法:

第一种是系统方法通过设置 navigationBarbarTintColor 颜色来改变状态栏颜色,另一种办法是我们自己写一个 UIView 作为背景添加到状态栏下面,这样就可以随意设置状态栏的颜色了

系统方法

1
2
3
self.navigationController.navigationBar.barTintColor = [UIColor redColor];
// UINavigationBar的半透明效果,默认为 YES
self.navigationController.navigationBar.translucent = NO;

如果你设置了 navigationBar- setBackgroundImage:(UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics ,那么上面的 setBarTintColor 就就失效了

自定义 View

创建一个 UIView,设置该 UIViewframestatusBar一样({0,-20,self.view.bounds.size.width,20}),然后设置该UIView 的背景色为你希望的状态栏的颜色,然后在 navigationBaraddSubViewUIView 即可,这种方式,可以使状态的背景颜色和导航栏的背景颜色区不一样

状态栏隐藏

状态栏隐藏和设置的状态栏的前景样式方法是类似的,也分为两种情况,一种是在 Info.plist 里面设置,一种是在 `` 里面设置

Info.plist 设置隐藏状态栏

同样的也可以使用 UIApplication 的方法隐藏,但是记住 View controller-based status bar appearance 的要设置为 NO

1
2
3
4
[[UIApplication sharedApplication] setStatusBarHidden:YES];
// 隐藏时候可以选择带动画的隐藏
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarStyleDefault];

有时候我们需要在 APP 启动页面隐藏状态栏,我们需要 Info.plist 里增加一个 Status bar is initially hidden 的键,设置为 YES,这样就 APP 启动页面就会隐藏状态栏

以上的方法也是在 iOS9 之后被废弃了,苹果推荐使用 UIViewController- prefersStatusBarHidden 方法

1
2
3
4
5
6
7
8
9
10
- (BOOL)prefersStatusBarHidden{
return YES;
}
// 状态隐藏显示的动画对应上面 UIApplication 的动画方法
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation{
return UIStatusBarAnimationSlide;
}

这个方法类似 preferredStatusBarStyle,也有一个 childViewControllerForStatusBarHidden 的方法和 - childViewControllerForStatusBarStyle 对应,作用和上面修改状态栏前景样式是一样的,就不再赘述了,但是有点不一样

  • UIViewController 即使和 UINavigationController 配合使用依然可以在自己的 - prefersStatusBarHidden 方法里面返回 YES 隐藏状态栏,只有当 UIViewController 有多个 childViewController 并且需要在某个 childViewController 里面隐藏状态栏,这时候才需要重写 UIViewControllerchildViewControllerForStatusBarHidden 返回需要隐藏状态栏的那个 childViewController
  • 另外,调用 - setNeedsStatusBarAppearanceUpdate 方法也会刷新 - prefersStatusBarHidden 方法

以上就是我关于 iOS 状态栏的设置的一些记录

本人刚开始写博客,主要是为了给自己的知识点做一个笔记,方便自己以后查阅,如果能让别人有所启发也是荣幸之至!如有错误,欢迎指正!