I need to let a specific ViewController embedded in an UINavigationController to have light status bar text color (but other ViewControllers to beh
Here's an improvement to Groot answer, in form of a simple category to UINavigationController, without the need to subclass UINavigationController.
Swift
extension UINavigationController {
override public func preferredStatusBarStyle() -> UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle() ?? .Default
}
}
Swift 3 & Swift 4
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
}
Objective-C
@implementation UINavigationController (StatusBarStyle)
- (UIStatusBarStyle)preferredStatusBarStyle
{
return [self.topViewController preferredStatusBarStyle];
}
@end
I used the first method you mentioned, I also found there's kinda bug when you used UINavigationController, it will never pass preferredStatusBarStyle call to it's child view controllers. What I have done is subclass the UINavigationController, and override preferredStatusBarStyle method as follows:
@implementation GLBaseNavigationController
- (UIStatusBarStyle)preferredStatusBarStyle
{
UIViewController *lastViewController = [self.viewControllers lastObject];
if ([lastViewController respondsToSelector:@selector(preferredStatusBarStyle)]) {
return [lastViewController preferredStatusBarStyle];
} else if ([super respondsToSelector:@selector(preferredStatusBarStyle)]) {
return [super preferredStatusBarStyle];
}
return UIStatusBarStyleDefault;
}
Then whenever I need a navigation controller, I use GLBaseNavigationController instead of UINavigationController. For storyboards, you need to specify the class of the navigation controller to your subclass as well.
To set UIStatusBarStyle individually for each UIViewController on UINavigationController stack you have to first subclass your UINavigationController and override childViewControllerForStatusBarStyle method.
In your UINavigationController subclass add:
-(UIViewController *)childViewControllerForStatusBarStyle {
return self.visibleViewController;
}
than you can set UIStatusBarStyle to whatever you want in every UIViewController using preferredStatusBarStyle method. Eg:
-(UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
For your first solution, I don't think you can change the status bar in viewDidLoad. If you have two ViewControllers stacked on top of each other, and each one toggles the status bar differently, that method will only get called once for each. You really want to change the status bar in viewWillAppear so that it gets called each time the page is shown. I also don't think you can rely on preferredStatusBarStyle since I'm also not sure how often/when that gets called. This is how you want to do it:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController.navigationBar setBarStyle:UIBarStyleDefault];
}
UIApplication.setStatusBarStyle(_:animated:) has been deprecated since iOS 9. According to Apple,
In iOS 7 and later, status bar behavior is determined by view controllers, and so calling this method has no effect by default. When view controller-based status bar appearance is disabled, this method behaves normally. To opt out of the view controller-based status bar appearance behavior, you must add the UIViewControllerBasedStatusBarAppearance key with a value of false to your app’s Info.plist file, but doing so is not recommended.
Setting the barStyle property is now (iOS 13+) considered a "legacy customization." According to Apple,
In iOS 13 and later, customize your navigation bar using the standardAppearance, compactAppearance, and scrollEdgeAppearance properties. You may continue to use these legacy accessors to customize your navigation bar's appearance directly, but you must update the appearance for different bar configurations yourself.
UINavigationController is a subclass of UIViewController (who knew
In your AppDelegate didFinishLaunch method, set the default status bar style, say:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault
animated:YES];
return YES;
}
Then, in your those two view controllers, where you want to change status bar, override following methods:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated]
// Here change status bar color
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent
animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear]
// Here bring back to color, that we set in AppDelegate
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault
animated:YES];
}