Alby's blog

世上没有巧合,只有巧合的假象。

0%

关于状态栏( UIStatusBar )的若干问题

一、概述

状态栏( UIStatusBar )指 iPhone/iPad/iPod 屏幕顶部用于显示网络、时间和电量等的、高度为20点的控件。状态栏的 windowLevelUIWindowLevelStatusBar ,而 window 的 windowLevelUIWindowLevelNormal 。所以一般情况下,状态栏位于 window 之上。

二、UIStatusBar 的位置和尺寸

1
2
NSString *statusBarFrame = NSStringFromCGRect([UIApplication sharedApplication].statusBarFrame);
NSLog(@"%@", statusBarFrame);

在 iPhone 6 竖屏测试输出:
2015-08-04 16:33:47.159 Test[6175:205261] {{0, 0}, {375, 20}}
在 iPhone 6 横屏测试输出:
2015-08-04 16:33:52.237 Test[6175:205261] {{0, 0}, {667, 20}}
在 iPhone 6 Plus 竖屏测试输出:
2015-08-04 16:35:54.365 Test[6175:205261] {{0, 0}, {414, 20}}
在 iPhone 6 Plus 横屏测试输出:
2015-08-04 16:35:56.716 Test[6175:205261] {{0, 0}, {736, 20}}

可见其中 origin.x 和 origin.y 总是0, size.height 总是20, size.width 依赖于不同设备及横竖屏。

三、UIStatusBarStyle (字体颜色)和背景颜色

UIStatusBarStyle 控制状态栏的字体颜色,在 iOS 7 只支持两种: UIStatusBarStyleDefaultUIStatusBarStyleLightContent 。注意,虽然目前表现出来的颜色是黑色或白色,但不是 Black 或 White 之类的,苹果留了一手以防以后改变。 Default 表示深色( Dark ),用于亮色( Light )背景; LightContent 表示亮色( Light ),用于深色( Dark )背景。当然这也不是强制的。
在没有导航栏的情况下,状态栏的背景颜色是透明的,可以在View里添加一个20点高度的子 View “伪造”一个背景;在有导航栏的情况下,状态栏的背景颜色和状态栏一样,看起来融为了一体。

四、App 启动时状态栏控制

App 启动的时候系统加载需要一定的时间,可以给 App 提供了 Launch Image 或 Launch Screen 以增强用户体验。在启动页显示出来的时候 App 还没有运行,也就谈不上在程序中控制状态栏的字体颜色、显示或隐藏。
默认情况下状态栏是显示出来的,并且 Style 为 UIStatusBarStyleDefault ,即黑色。

1、隐藏

可以在 Info 中将 Status bar is initially hidden(UIStatusBarHidden) 对应的 Value 设置为 Yes 。也可以在 General 中将 Hide status bar 勾选:

实际上,上面两种设置方法最终作用到 info.plist 文件。可以直接修改该文件,如果不嫌麻烦又不担心出错的话。如果没有使用基于 ViewController 的状态栏控制,并且 App 内部又需要将状态栏显示出来,可以在 AppDelegate 中设置:

1
[[UIApplication sharedApplication] setStatusBarHidden:NO];

2、设置字体颜色为白色

可以在 Info 中将 Status bar style(UIStatusBarStyle) 对应的 Value 设置为 UIStatusBarStyeLightContent 。也可以在 General 中将 Status Bar style 选择为 Light

同样的,上面两种设置方法最终作用到 info.plist 文件。如果没有使用基于 ViewController 的状态栏控制,并且 App 内部又需要将状态栏颜色改为黑色,可以在 AppDelegate 中设置:

1
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

五、App 运行时状态栏控制

新建一个 Xcode 项目,App 默认是基于 ViewController 的状态栏控制,即在 ViewController 重载 prefersStatusBarHiddenpreferredStatusBarStylepreferredStatusBarUpdateAnimation 三个方法,及在必要时调用 setNeedsStatusBarAppearanceUpdate 方法。
如果要使用iOS 7之前的通过 UIApplication 控制状态栏,需在 target 的info.plist中增加一条 View controller-based status bar appearance(UIViewControllerBasedStatusBarAppearance) 并设置为 NO

1、View controller-based status bar appearance : YES 或 info.plist 无此条目

UIViewController 方法 说明
- (BOOL)prefersStatusBarHidden NS_AVAILABLE_IOS(7_0); // Defaults to NO 询问是否隐藏状态栏。
- (UIStatusBarStyle)preferredStatusBarStyle NS_AVAILABLE_IOS(7_0); // Defaults to UIStatusBarStyleDefault 询问状态栏样式( UIStatusBarStyleDefault/UIStatusBarStyleLightContent )。
// Override to return the type of animation that should be used for status bar changes for this view controller. This currently only affects changes to prefersStatusBarHidden.
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation NS_AVAILABLE_IOS(7_0); // Defaults to UIStatusBarAnimationFade
询问状态栏显示或隐藏动画。
// This should be called whenever the return values for the view controller’s status bar attributes have changed. If it is called from within an animation block, the changes will be animated along with the rest of the animation block.
- (void)setNeedsStatusBarAppearanceUpdate NS_AVAILABLE_IOS(7_0);
设置需要更新状态栏。主动调用该方法,将间接调用上述三个方法。如果需要动画生效,需:
[UIView animateWithDuration:0.4 animations:^{ [self setNeedsStatusBarAppearanceUpdate]; }];

2、View controller-based status bar appearance : NO

UIApplication 方法/属性 说明
// Setting statusBarHidden does nothing if your application is using the default UIViewController-based status bar system.
@property(nonatomic,getter=isStatusBarHidden) BOOL statusBarHidden;
- (void)setStatusBarHidden:(BOOL)hidden withAnimation:(UIStatusBarAnimation)animation NS_AVAILABLE_IOS(3_2);
设置是否隐藏状态栏。
// Setting statusBarHidden does nothing if your application is using the default UIViewController-based status bar system.
@property(nonatomic) UIStatusBarStyle statusBarStyle; // default is UIStatusBarStyleDefault
- (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle animated:(BOOL)animated;
设置状态栏样式( UIStatusBarStyleDefault/UIStatusBarStyleLightContent )。

六、示例代码

可以根据是否是基于 ViewController 的状态栏控制来决定是否调用 UIApplication 中控制状态栏的相关方法,也可以直接调用。因为在基于 ViewController 的状态栏控制时,调用 UIApplication 中控制状态栏的相关设置方法会被忽略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@interface ViewController ()

@property (nonatomic) BOOL statusBarIsHidden;

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.statusBarIsHidden = NO;
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];

[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;

[self performSelector:@selector(setStatusBarHidden:) withObject:@(YES) afterDelay:3.];
[self performSelector:@selector(setStatusBarHidden:) withObject:@(NO) afterDelay:6.];
}

- (void)setStatusBarHidden:(BOOL)hidden
{
self.statusBarIsHidden = hidden;
[UIView animateWithDuration:0.4
animations:^{
[self setNeedsStatusBarAppearanceUpdate];
}];
[[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationSlide];
}

- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleDefault;
}

- (BOOL)prefersStatusBarHidden
{
return self.statusBarIsHidden;
}

- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation
{
return UIStatusBarAnimationSlide;
}

@end

七、自定义状态栏

见参考资料:
在状态栏上做渐变动画效果
定制 iOS 7 中的导航栏和状态栏
遮挡 iPhone 系统栏实现自定义状态栏的代码
把 UIView 覆盖到状态栏上的方法

环境:

  • macOS 10.10.5
  • Xcode 6.4(6E35b)
  • iOS >= 7.0