Pregunta

(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?

¿Fue útil?

Solución

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

Otros consejos

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.

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.

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.

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.

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top