I need to let a specific ViewController embedded in an UINavigationController
to have light status bar text color (but other ViewController
s 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];
}