How to change iOS status bar color in child view controller
Asked Answered
W

6

10

(iOS 7 Xcode 5.0.2)

I used following methods, successfully change the status bar color to white on root view controller

[self setNeedsStatusBarAppearanceUpdate]; // Update status bar style

-(UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent; // Set status bar color to white
}

Now I'm trying to change status bar color to black when navigate to child view controller, I don't know how to do it.(status bar color is still white)

I searched, and find this method: childViewControllerForStatusBarStyle I read Apple's document,But still don't know how to/where to use it, and I'm not sure if this is the right approach

Anyone knows how to change status bar color in child view controller?

Warga answered 18/1, 2014 at 17:57 Comment(2)
Is your child view controller inside a navigation controller?Kimberelykimberlee
@JamesFrost Yes, it is.Warga
K
13

By default, it seems that UINavigationController unfortunately doesn't provide a sensible default implementation of childViewControllerForStatusBarStyle. By implementing this method, you can tell your navigationController to defer all calls to preferredStatusBarStyle to its topmost childViewController.

You could either subclass UINavigationController and implement the method there, or simply add a category:

@implementation UINavigationController (ChildStatusBarStyle)

- (UIViewController *)childViewControllerForStatusBarStyle 
{
    return self.topViewController;
}

@end
Kimberelykimberlee answered 19/1, 2014 at 9:40 Comment(7)
I am not sure if supplying a category on a method that is declared in a subclass (UINavigationController inherits UIViewController) method is such a good idea - if I am not mistaken, this leads to undefined behaviour as a category is not a proper override. Hence I would suggest going with the subclassing instead. Still, its a good answer! (+1)Unaccompanied
@JamesFrost Really good suggestion,I'm starting to figure out how to use it now. Let me try it and get back to you later. Thanks very much! (+1)Warga
@JamesFrost From the documentation: The UINavigationController class implements a specialized view controller that manages the navigation of hierarchical content. This class is not intended for subclassing. Instead, you use instances of it as-is in situations where you want your application’s user interface to reflect the hierarchical nature of your content. I think it UINavigationControler is not sugguested for subclassing by Apple. Is there any other approach?Warga
@Unaccompanied Hi Till, Take a look at the info above~Warga
Hmm... I've just created a new Xcode project with a single viewController. I implemented preferredStatusBarStyle to return UIStatusBarStyleLightContent, and then created a UINavigationController category containing the above method - and it worked straight away.Kimberelykimberlee
@JamesFrost I know what went wrong: I forget to embed my view controller inside the navigation controller... Thanks a lot, your answer works fine~Warga
@Unaccompanied On the contrary Apple's API is not very friendly with subclassing objects. Using extension is well supported and works as expected.Atheroma
W
1

I just find out: When you embed the root view controller inside UINavigationController correctly, You'd never need to create a category to expand the capability of navigation controller, or subclassing UINavigationController for the same purpose.

You just need to put preferredStatusBarStyle inside every view controller, and remember to call [self setNeedsStatusBarAppearanceUpdate]; to update status bar style. Simple as it is!

check out this video from WWDC 2013: Click Here


EDIT:

The reason I made it working, is I happen to set UINavigationBar hidden. In this case, it behaves the same when not using UINavigationController at all. When you Trying to change StatusBarStyle of an UIViewController which is inside UINavigationController stack. It will fail to work in this way. It only works in individual UIViewController. The WWDC 2013 Video example is not using UINavigationController, so that why the approach is working fine.

Warga answered 21/1, 2014 at 14:40 Comment(3)
Could you specify what "embed the root view controller inside UINavigationController correctly" means? I created a simple blank project and currently have a UIViewController embedded via storyboard. The preferredStatusBarStyle is never called.Plump
@Plump You are right. and My answer above is misleading. The reason I made it working, is I happen to set UINavigationBar hidden. In this case, it behaves the same when not using UINavigationController at all.Warga
@Plump When you Trying to change StatusBarStyle of an UIViewController which is inside UINavigationController stack. It will fail to work in this way. It only works in individual UIViewController. The WWDC 2013 Video example is not using UINavigationController, so the approach is working fine. You probably want to the other way :)Warga
C
1

James Frost answer was the only one that worked for me. Thank you! Here's a Swift 4 version of that code.

extension UINavigationController {
override open var childViewControllerForStatusBarStyle: UIViewController? {
    return topViewController
}
}

Note: this is a bit unwieldy as-is, I recommend adding some code to limit its scope to a single viewController. Something like this:

extension UINavigationController {
override open var childViewControllerForStatusBarStyle: UIViewController? {
    if topViewController is MyViewController {
        return topViewController
    } else {
        return nil
    }
}
}

You'll obviously need to replace MyViewController with your UIViewController subclass that implements preferredStatusBarStyle.

override var preferredStatusBarStyle: UIStatusBarStyle {
    if isBackgroundDark() {
        return .lightContent
    } else {
        return .default
    }
}

Again isBackgroundDark() is yours to implement.

Finally don't forget to call setNeedsStatusBarAppearanceUpdate() in your viewController every time isBackgroundDark() changes its value.

Chiliad answered 20/10, 2018 at 0:1 Comment(0)
B
0

In contrast to what James Frost said, and after much time spent debugging why my Browser Activities had wrong StatusBar colors (Swift):

override func childViewControllerForStatusBarStyle() -> UIViewController? {
    return visibleViewController
}

That said: In some scenarios .topViewController is right, in others like with UIActivities it's .visibleViewController.

Bwana answered 7/3, 2016 at 4:32 Comment(0)
O
0

Thanks to @James Frost, the solution works well.
I didn't make it work at first, so I want to make a further explanation about it.

If you have a subclass of UINavigationController, it's important to add preferredStatusBarStyle in your UINavigationController subclass at the same time.

- (UIStatusBarStyle)preferredStatusBarStyle
{
  return UIStatusBarStyleLightContent;
}

And add childViewControllerForStatusBarStyle in extension of UINavigationController.

extension UINavigationController {
  override open var childViewControllerForStatusBarStyle: UIViewController? {
    return visibleViewController
  }
}

BTW, it's OK that UINavigationController subclass and extension of UINavigationController use different coding language, still work.

Oren answered 6/3, 2019 at 9:28 Comment(0)
S
0

I've tried another solutions and noticed that the Status Bar doesn't update without setNeedsStatusBarAppearanceUpdate(). There can be multiple places to call this marker, but the easies way is to override viewControllers setter.

class StatusBarNavigationController: UINavigationController {
    override var childForStatusBarHidden: UIViewController? {
        return topViewController
    }

    override var viewControllers: [UIViewController] {
        didSet { setNeedsStatusBarAppearanceUpdate() }
    }
}

Then you can use the StatusBarNavigationController programmatically or on a Storyboard.

Still answered 3/4, 2019 at 11:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.