Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide status bar only on modally presented view controller

I have a view controller A that shows the status bar on top. From that view controller I want to present another view controller B that hides the status bar. In order to achieve that I override the property

override var prefersStatusBarHidden: Bool {
    return true
}

on B. For enforcing a smooth animation whenever the status bar (dis)appears I also override the property

override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
    return .slide
}

However, when I now present view controller B from A the status bar disappears abruptly while A is still visible, right before the animated modal transition begins.

I'm searching for a way to fix this "jumping status bar" behavior. Ideally, I would like to have a clean separation:

  • A: shows status bar
  • B: does not show status bar

so that, when I present B, the status bar is covered by it.

As the status bar seems to be a global view that doesn't belong to any particular view controller it's probably difficult to achieve that kind of behavior. So in case it's not possible to replicate this exact animation behavior, I'd also be happy if the status bar slides out smoothly during the view controller transition. How can I achieve that?

like image 239
Mischa Avatar asked Jun 12 '17 15:06

Mischa


1 Answers

For animating the status bar during the transition, you could do something like this in view controller B:

var willAppear = false

override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
    return .slide
}

override var prefersStatusBarHidden: Bool {
    return willAppear
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)
    willAppear = true
    UIView.animate(withDuration: 0.5) {
        self.setNeedsStatusBarAppearanceUpdate()
    }
}

Then I guess you would need to do the opposite if you want the reverse effect when the modal controller is dismissed.

You can adjust the duration of the animation to whatever suits you, though I'm not sure how consistent the duration between viewWillAppear and the modal controller actually being fully presented will be.

EDIT:

"Opposite" ends up being something like this (in view controller A):

var willAppear = false

override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
    return .slide
}

override var prefersStatusBarHidden: Bool {
    return willAppear
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if let _ = presentedViewController as? B {
        willAppear = true
    }
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)
    if let _ = presentedViewController as? B {
        willAppear = false
        UIView.animate(withDuration: 0.5) {
            self.setNeedsStatusBarAppearanceUpdate()
        }
    }
}

Which I agree, is way too much code for something that I imagine many people want.

like image 84
Samantha Avatar answered Oct 31 '22 11:10

Samantha