21
votes

I have an issue in iOS7 where a normal UINavigationController pushed view controller has the correct status bar text color for the UINavigationController navbar color (which is a light gray, almost white so the status bar text is black). However, when a "modal" view controller is presented using -presentViewController:animated:completion:, the status bar text color is changed to white and is very hard to see given the color of the navbar. Navbar color is always the same across the whole app and does not change for each view controller. This happens on every -presentViewController call.

"View controller-based status bar appearance" is set to YES.

I am not sure what to look at to try and solve this.

9
Surely the real issue to solve is the changing background colour on modal popup? Changing the status bar text colour doesn't address the root problemHughHughTeotl
This discusses some solutions, but they are a bit hackish: blog.ijasoneverett.com/2013/09/…HughHughTeotl

9 Answers

15
votes

The navigation controller decides whether to have a light or dark content based on its navigation bar's barStyle property. The default, UIBarStyleDefault, means the navigation bar has a light color and the status bar will have dark content. Changing this property to UIBarStyleBlack doesn't actually make the navigation bar black (the color of the navigation bar is still set using barTintColor), but it tells it that it has a dark color. The navigation controller then decides that, since the navigation bar is dark, it should set the status bar content to light.

It appears that on your main navigation controller (on which you push things) the barStyle is indeed set to UIBarStyleBlack somewhere. You have to do the same thing to the modally presented navigation controller, like so:

UINavigationController *newViewController = [[UINavigationController alloc] initWithRootViewController:modalViewController];
newViewController.navigationBar.barStyle = self.navigationController.navigationBar.barStyle;
[self presentViewController:newViewController animated:YES completion:nil];
15
votes

set YourModalViewControler.modalPresentationCapturesStatusBarAppearance to YES and keep "View controller-based status bar appearance" to YES.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.modalPresentationCapturesStatusBarAppearance = YES;
    ....
}

then overwrite preferredStatusBarStyle

- (UIStatusBarStyle)preferredStatusBarStyle {
    return TheStyleYouWant;
}
2
votes

You can redefine the preferredStatusBarStyle method in your navigation controller class

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
// or UIStatusBarStyleBlackOpaque, UIStatusBarStyleBlackTranslucent, or UIStatusBarStyleDefault

}

and you can also define a "view did load method" to set custom colors you want

- (void) viewDidLoad
{
    UIColor *barColor = [UIColor whitecolor];

    UIView *colorView = [[UIView alloc] initWithFrame:CGRectMake(0.f, -20.f, 320.f, 64.f)];
    colorView.opaque = NO;
    colorView.alpha = .5f;
    colorView.backgroundColor = barColor;

    self.navigationBar.barTintColor = barColor;
    self.navigationBar.tintColor = [UIColor whiteColor];
    [self.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];

    /*self.navigationController.navigationBar.barTintColor = [UIColor blackColor];
     self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
     [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]}];
     self.navigationController.navigationBar.translucent = NO;*/

    [self.navigationBar.layer insertSublayer:colorView.layer atIndex:0];

}
2
votes

I just figured out how to do that. I had the exact same problem and it seems that it works like a charm!

The first thing you need to do is to change an attribute in you .plist file of your project to NO. The attribute is: "View controller-based status bar appearance". If the attribute doesn't exist, don't hesitate to add a new one exactly as I just written to you (without quotes).

The second thing is to add to each view controller's viewDidLoad method

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

if you want your status bar's text to be white or

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];

if you want your status bar's text to be black.

That's all!

2
votes

This works. But I'm not happy with it because it a bit hacky. I think it's a bug that preferredStatusBarStyle is not called for modal view. Will ask Apple.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
    [self setNeedsStatusBarAppearanceUpdate];
}


- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
    [self setNeedsStatusBarAppearanceUpdate];
}
2
votes

Set UIViewControllerBasedStatusBarAppearance to NO in your info.plist

1
votes

I was having the same problem as you were having. The info.plist was correct and everywhere else preferredStatusBarStyle was called correctly. But not in my modal view. That is because preferredStatusBarStyle was sent to the navigation controller. So I made a subclass of UINavigationController that passed on preferredStatusBarStyle to the view controller it was presenting, and voila, all was behaving as it should again

0
votes

Having reviewed all the answers provided here and in other answers, I have found that the only solution that worked for me was to create a vacuous navigation bar for the view controller I am presenting modally.

This may not work for you, but it works for me for the following reasons:

  1. My modal dialog has a navigation bar anyways (although it is not used for navigation; it is simply used to either save or dismiss the results.
  2. The status bar color has already been defined application-wide in applicationDidFinishLaunching as discussed above, and it has a custom colour.

It's somewhat annoying from an engineering perspective to have a navigation controller that effectively does nothing, but without one I was unable to get past this problem.

0
votes

My solution:

newViewController.modalPresentationStyle = .fullScreen

By default, UINavigationController decides the status bar style and overrides all sub view controllers styles. However, when a modal view controller is fullscreen, its method preferredStatusBarStyle is called.