概述
iOS 项目中一个视图控制器里, 类似今日头条那种的分栏显示很多子控制器. 在第一个子控制器里内嵌了一个H5页面, 如下图所示:
图里的
NBBaseWebVC
是最上层的一个自定义的 WebView
控制器, 这里放了一个测试的斗鱼直播页面。这个斗鱼直播页面的视频是支持全屏播放的,全屏播放状态下,默认 statusBar
是隐藏状态的。因此当退出全屏播放后,如果对状态栏不做任何处理,那么就会保持状态栏隐藏的状态,看起来是导航栏被上移了。
分析
合适的时机
导航栏上移了,咋办,有啥法子呢。如上段分析,之所以上移了,原因是因为状态栏被隐藏了,所以只能往状态上做文章了。我们需要在合适的时机告诉系统,嘿,哥们,我们已经不全屏播放了,回到垂直的状态了,麻烦你把状态栏给我搞回来吧。
这个合适的时候就是退出全屏播放的时候,那么我们怎么知道即将退出全屏播放呢。这个地方有个小技巧,当 H5 页面进行全屏播放的时候,是需要新建个 window
的,即将退出全屏播放的状态,就是这个窗口即将消失的状态。只要我们监听了 UIWindow
的 didBecomeHiddenNotification
通知,就能得到这个合适的时机,在这个通知的方法里面,告诉系统:来吧,让我们更新下状态栏的状态吧。这个告诉系统状态栏的方法就是 setNeedsStatusBarAppearanceUpdate
,调用这个方法之后,系统就会重新读取控制器的 prefersStatusBarHidden
属性,我们要做的工作就是在当前控制器里重写这个属性,返回正确的值。如下:
override var prefersStatusBarHidden: Bool {
return UIApplication.shared.statusBarOrientation.isLandscape
}
狡猾的 prefersStatusBarHidden
大多数情况下,如果只在当前控制器里重写 prefersStatusBarHidden
,会发现状态栏并没有达到我们想要的效果。奇怪啊,我已经告诉当前控制器,给我把状态栏给改了,怎么没有起到效果呢。别着急,来进行如下的检查游戏吧。
Info.plist 设置
View controller-based status bar appearance
在 info.plist
中必须设置为 YES。
控制器的层级
如果当前的 viewController
被一个自定义的导航控制器包裹,导航控制器又被 TabBarViewController
控制,结构如: UITabViewController(自定义)
-> UINavigationController(自定义)
-> UIViewController
,那么就需要在上面的三个类中都重写
prefersStatusBarHidden
来完成设置,我的实践代码如下:
UITabViewController(自定义)
override open var prefersStatusBarHidden: Bool {
return self.selectedViewController?.prefersStatusBarHidden ?? false
}
selectedViewController
是当前的导航控制器
UINavigationController(自定义)
override open var prefersStatusBarHidden: Bool {
return self.topViewController?.prefersStatusBarHidden ?? false
}
topViewController
是当前播放视频的控制器
UIViewController(当前控制器)
override var prefersStatusBarHidden: Bool {
return UIApplication.shared.statusBarOrientation.isLandscape
}