Status Bar 的正常隐藏
view-controllers 控制 status bar 的隐藏
在iOS 9中,status bar 的隐藏默认是通过 view-controlls 控制的,即每个控制器决定是否隐藏 status bar 。
只需在 controller 中重载 prefersStatusBarHidden
函数
override func prefersStatusBarHidden() -> Bool {
return true
}
全局控制 status bar 的隐藏
如果想要全局控制,只需两步:
- 在Info.plist中,添加属性
View controller-based status bar appearance
为NO
- 添加如下代码
UIApplication.sharedApplication().statusBarHidden = true
- 如果想改成每个控制器自行控制,将
View controller-based status bar appearance
为YES
即可
Status Bar 隐藏不了的情况
但是,有时候也会有意外发生,上述方法并不能如愿隐藏 status bar ,那就是 在ParentViewController 中添加一个全屏的 ChildViewController ,此时想用ChildViewController 来控制状态栏时 ,就会失效,即使 ChildViewController 中的prefersStatusBarHidden
方法返回的是YES
,也无法隐藏 status bar 。
解决办法是:重载 childViewControllerForStatusBarHidden
方法
如果你想要让你的 container view controller 的 child view controller 控制 status bar 的隐藏状态的话,就重载该方法,决定使用哪个 child view controller 来控制 隐藏/非隐藏 的状态。如果返回 nil 或不重载该方法,就用它自己来控制 status bar 的状态。可以通过调用 setNeedsStatusBarAppearanceUpdate
方法来改变该方法返回的值,即再调用该方法一次。
class StatusBarHiddenParentController: UIViewController {
var childController: StatusBarHiddenChildController?
override func viewDidLoad() {
super.viewDidLoad()
childController = StatusBarHiddenChildController.fromStoryboard("Main")
addChildViewController(childController!)
view.addSubview(childController!.view)
setNeedsStatusBarAppearanceUpdate()
}
override func childViewControllerForStatusBarHidden() -> UIViewController? {
return childController
}
override func prefersStatusBarHidden() -> Bool {
return false
}
}
class StatusBarHiddenChildController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
上述代码最终能将状态栏隐藏,即使在 StatusBarHiddenParentController 中的prefersStatusBarHidden
返回的是NO
注意:因为childViewControllerForStatusBarHidden
会比viewDidLoad
先调用,所以在viewDidLoad
中要调用setNeedsStatusBarAppearanceUpdate
有时候我们需要关闭控制器视图,如下列三种情况:
- 将控制器从navigationController的堆栈中pop出去
- 将present出来的控制器dismiss掉
- 将子控制器从父控制器中移除
push 和 present 两种方式展示的 view controller 在 pop 和 dismiss 时都能够自动还原 status bar 的状态。但是,把子控制器从父控制器中移除时,就会出现奇怪的问题, status bar并不能自动还原,因此还需要特别处理。
我们可以设置一个Bool变量 statusBarHidden
用来记录目前 statusBar 是否隐藏,在 prefersStatusBarHidden
函数中返回 statusBarHidden
值。在要移除子控制器的函数中做两步操作:
- 先将
statusBarHidden
设置为False
, 并调用setNeedsStatusBarAppearanceUpdate
刷新状态栏 - 再将子控制器移除。
class StatusBarHiddenRemoveWayChildController: UIViewController {
var statusBarHidden: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
let removeButton = UIButton(frame: CGRectMake(30, 80, 100, 30))
removeButton.setTitle("remove", forState: .Normal)
removeButton.addTarget(self, action: "remove", forControlEvents: .TouchUpInside)
view.addSubview(removeButton)
}
// 1. set `statusBarHidden` into `false`, and then refresh status bar
// 2. remove from parent controller
func remove() {
statusBarHidden = false
setNeedsStatusBarAppearanceUpdate()
view.removeFromSuperview()
removeFromParentViewController()
}
override func prefersStatusBarHidden() -> Bool {
return statusBarHidden
}
}
滚动ScrollView或TableView时隐藏Status Bar和Navigation Bar
京东和淘宝客户端的商品搜索结果页面,在滚动时可以隐藏 status bar 和 navigation bar ,我自认为这是一个很好的设计,身为一个有追求的程序员,这个功能的实现那当然也不能放过啦~~
NavigationController 有一个属性 hidesBarsOnSwipe
,可以实现轻扫时隐藏 navigation bar ,与之对应的手势是它的另一个属性barHideOnSwipeGestureRecognizer
,只要给这个手势添加一个方法来控制 status bar ,就可以实现同时隐藏 status bar 和 navigation bar 了。
class StatusBarAndNavigationBarHiddenOnSwipeController: UITableViewController {
var hideStatusBar = false
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.grayColor()
navigationController?.barHideOnSwipeGestureRecognizer.addTarget(self, action: "swipe:")
navigationController?.hidesBarsOnSwipe = true
}
override func prefersStatusBarHidden() -> Bool {
return hideStatusBar
}
func swipe(recognizer: UISwipeGestureRecognizer) {
hideStatusBar = navigationController?.navigationBar.frame.origin.y < 0
UIView.animateWithDuration(0.2) { () -> Void in
self.setNeedsStatusBarAppearanceUpdate()
}
}
override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
return .Slide
}
}