I have made following common method for hiding and showing again status bar. It works fine before iOS 13, but I am getting following crash while I run it for device having iOS 13 or greater.
+(void)showStatusBar:(BOOL)show
{
UIView *statusBar = [[[UIApplication sharedApplication] valueForKey:#"statusBarWindow"] valueForKey:#"statusBar"];
if ([statusBar respondsToSelector:#selector(setBackgroundColor:)]) {
[[UIApplication sharedApplication] setStatusBarHidden:!show withAnimation:UIStatusBarAnimationNone];
}
}
Getting following error for iOS 13
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'App called -statusBar or
-statusBarWindow on UIApplication: this code must be changed as there's no longer a status bar or status bar window. Use the
statusBarManager object on the window scene instead.'
What can I do to hide and show status bar for some view controllers only?
If you want to show/hide the status bar on the different View Controllers you need to:
Add View controller-base status bar appearance option in your Info.plist and set it to YES
Override var prefersStatusBarHidden: Bool in each View Controller where you want to have the status bar shown/hidden
override var prefersStatusBarHidden: Bool {
return true
}
If you want to show/hide it dynamically (ex. after tapping on button), you could do something like this:
var statusBarHidden = true {
didSet {
setNeedsStatusBarAppearanceUpdate()
}
}
override var prefersStatusBarHidden: Bool {
return statusBarHidden
}
You could find more verbose explanation here Here
Also in the Apple Documentation for UIStatusBarManager you can find the following quote:
You do not use this object to modify the configuration of the status bar. Instead, you set the status bar configuration individually for each of your UIViewController objects. For example, to modify the default visibility of the status bar, override the prefersStatusBarHidden property of your view controller.
Related
I would like to show and hide the Status bar on some controllers. Can this be done or is it more of an overall app setting.
I have seen many posts/questions about the plist update:
View controller-based status bar appearance - NO
If this is completed what control is then given?
I am looking to show the status bar on the main screen of the application. But for example on a side (slide) menu I would like it not to show, is this possible? Can this be changed in IB or code?
EDIT --
I am using a https://github.com/edgecase/ECSlidingViewController implementation.
The main controller (showing the first page) should show the Status bar, but the left menu controller when it slides should not.
I believe the issue is that they both sit within the same root controller (sliding view controller) so it is difficult to complete.
Ideally if the home screen (main page) could take the status bar with it when it slides that would look best.
The plist setting "View controller-based status bar appearance" only controls if a per-controller based setting should be applied on iOS 7.
If you set this plist option to NO, you have to manually enable and disable the status bar like (as it was until iOS 6):
[[UIApplication sharedApplication] setStatusBarHidden:YES]
If you set this plist option to YES, you can add this method to each of your viewControllers to set the statusBar independently for each controller (which is esp. nice if you have a smart subclass system of viewControllers)
- (BOOL)prefersStatusBarHidden {
return YES;
}
Edit:
there are two more methods that are of interest if you are opting in the new viewController-based status bar appearance -
Force a statusbar update with:
[self setNeedsStatusBarAppearanceUpdate]
If you have nested controllers (e.g. a contentViewController in a TabBarController subclass, your TabBarController subclass might ask it's current childViewController and forward this setting. I think in your specific case that might be of use:
- (UIViewController *)childViewControllerForStatusBarHidden {
return _myChildViewController;
}
- (UIViewController *)childViewControllerForStatusBarStyle {
return _myOtherViewController;
}
On iOS 7 and later, just implement -prefersStatusBarHidden, for example in a UIViewController that should hide the status bar:
- (BOOL)prefersStatusBarHidden {
return YES;
}
The default is NO.
Swift 3:
override var prefersStatusBarHidden: Bool {
return true
}
You can also show/hide the status bar in an animation block, by putting animation code inside didSet property of variable that describes whether it should be shown or hidden. When you set a new value for the statusBarHidden Bool, this automatically triggers the animated updating of the status bar over the duration you have chosen.
/// Swift 3 syntax:
var statusBarHidden: Bool = true {
didSet {
UIView.animate(withDuration: 0.5) { () -> Void in
self.setNeedsStatusBarAppearanceUpdate()
}
}
}
override var prefersStatusBarHidden: Bool {
return statusBarHidden
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
statusBarHidden = false // show statusBar, animated, by triggering didSet block
}
Swift version of Mojo66's answer:
override func prefersStatusBarHidden() -> Bool {
return true
}
How do you hide the status bar in ios 9?
This is now deprecated:
[UIApplication sharedApplication] setStatusBarHidden:YES];
Swift-3
override var prefersStatusBarHidden: Bool {
return true
}
I got the Information From Here
Change func to var
Delete ()
Change -> to :
This works because a computed variable has a getter function, so the function you were implementing before simply turns into the getter function
2016 onwards: simple Thing like
On your info.plist add the following two property for statusBar Hidden
View controller-based status bar appearance (Boolean: NO)
Status bar is initially hidden (Boolean: YES)
By Source
<key>UIStatusBarHidden</key>
<true/>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
or
Old answers ! ...
add application.statusBarHidden in didFinishLaunchingWithOptions
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
application.statusBarHidden = YES;
return YES;
}
and add
in info.plist add this View controller-based status bar appearance set NO
View controller-based status bar appearance = NO
viewcontroller based hidden set
Add method in your view controller.
Objective -C
- (BOOL)prefersStatusBarHidden {
return YES;
}
Swift upto 2
override func prefersStatusBarHidden() -> Bool {
return true
}
(GOOD) 2016.5.17 in iOS 9.0 worked nicely.
Updated Answer
Go to Info.plist file
Hover on one of those lines and a (+) and (-) button will show up.
Click the plus button to add new key
Type in start with capital V and automatically the first choice will be View controller-based status bar appearance. Add that as the KEY.
Set the VALUE to "NO"
Go to you AppDelegate.m for Objective-C (for swift language: AppDelegate.swift)
Add the code, inside the method
For Objective-C:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[application setStatusBarHidden:YES];
return YES;
}
For Swift:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject:AnyObject]?) -> Bool {
application.statusBarHidden = true
return true
}
in info.plist add the following two property.
View controller-based status bar appearance (NO)
Status bar is initially hidden (YES)
I know that the documentation of setStatusBarHidden: does not mention on what use instead. But the header of UIApplication does.
// Setting statusBarHidden does nothing if your application is using the default UIViewController-based status bar system.
#property(readwrite, nonatomic,getter=isStatusBarHidden) BOOL statusBarHidden NS_DEPRECATED_IOS(2_0, 9_0, "Use -[UIViewController prefersStatusBarHidden]");
- (void)setStatusBarHidden:(BOOL)hidden withAnimation:(UIStatusBarAnimation)animation NS_DEPRECATED_IOS(3_2, 9_0, "Use -[UIViewController prefersStatusBarHidden]");
Here is stated that you should use the prefersStatusBarHidden on UIViewController and use view controller based statusbar styles.
All you need to do now is configure whether the view controller needs to show of hide the status bar. Like so :
- (BOOL)prefersStatusBarHidden {
return YES;
}
Here's how do you easily return a control over status bar visibility for iOS 9+ and Swift 3+:
Add View controller-based status bar appearance key with YES value to Info.plist.
Add this variable to the view controller:
private var isStatusBarHidden = false {
didSet {
setNeedsStatusBarAppearanceUpdate()
}
}
Override prefersStatusBarHidden property:
override var prefersStatusBarHidden: Bool {
return isStatusBarHidden
}
That's it. Now you are able to call isStatusBarHidden = true and isStatusBarHidden = false whenever you want.
An easy approach would be to set the windowLevel of the Application to be either normal or statusBar based on your needs, so to start
Objective-C
To Hide the Status Bar
UIApplication.sharedApplication.keyWindow.windowLevel = UIWindowLevelStatusBar;
To Show the Status Bar
UIApplication.sharedApplication.keyWindow.windowLevel = UIWindowLevelNormal;
Also add the Key (View controller-based status bar appearance) with boolean value NO.
If for some reason you need View controller-based status bar appearance equal to YES (for example to keep status bar white)
on AppDelegate's didFinishLaunchingWithOptions method or wherever you setup your navigationController:
yourNavigationController.navigationBar.barStyle = .black
then use alex-staravoitau's awesome answer and add this code wherever you'll be hiding the status bar:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
I'm not sure if this is the right way to achieve this result, but it worked for me and I hope it helps someone else too :)
In most of the iOS it will work. I have tested with iOS 10.
Open info.plist
"View controller-based status bar appearance" set to NO
"Status bar is initially hidden" set to YES
Done
I need to let a specific ViewController embedded in an UINavigationController to have light status bar text color (but other ViewControllers to behave differently). I am aware of at least 3 methods, none of which however work in my case.
How to change Status Bar text color in iOS 7, the method is primarily:
Set the UIViewControllerBasedStatusBarAppearance to YES in the plist
In viewDidLoad do a [self setNeedsStatusBarAppearanceUpdate];
Add the following method:
- (UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
Running on iOS 7.0.3, this method does not work for me, since even after I have implemented all 3 steps correctly, preferredStatusBarStyle is never called.
UIStatusBarStyle PreferredStatusBarStyle does not work on iOS 7, the method is primarily:
Setting your navigationBar’s barStyle to UIBarStyleBlackTranslucent will give white status bar text (ie. UIStatusBarStyleLightContent), and UIBarStyleDefault will give black status bar text (ie. UIStatusBarStyleDefault).
This method works fair and square on iPhone, but not on iPad.
Setting the UIViewControllerBasedStatusBarAppearance to NO in the plist, and use
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
This clearly doesn't apply in this case, since I need to only specify different status bar colors for two of the ViewControllers.
Thanks for all help!
For people having this problem with a UINavigationController I can recommend creating a custom UINavigationController and implementing the preferredStatusBarStyle on it like this:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return [self.topViewController preferredStatusBarStyle];
}
That way the statusbar style will be that of the top view controller. Now you can implement the view controller's preferredStatusBarStyle anyway you like.
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
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;
}
iOS 13 Solution(s)
Regarding your attempt #3 - DEPRECATED
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.
Regarding your attempt #2 - LEGACY
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.
Regarding your attempt #1 - You were on the right track!
UINavigationController is a subclass of UIViewController (who knew 🙃)!
Therefore, when presenting view controllers embedded in navigation controllers, you're not really presenting the embedded view controllers; you're presenting the navigation controllers! UINavigationController, as a subclass of UIViewController, inherits preferredStatusBarStyle and childForStatusBarStyle, which you can set as desired.
Any of the following methods should work:
Override preferredStatusBarStyle within UINavigationController
preferredStatusBarStyle (doc) - The preferred status bar style for the view controller
Subclass or extend UINavigationController
class MyNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
OR
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
Override childForStatusBarStyle within UINavigationController
childForStatusBarStyle (doc) - Called when the system needs the view controller to use for determining status bar style
According to Apple's documentation,
"If your container view controller derives its status bar style from one of its child view controllers, [override this property] and return that child view controller. If you return nil or do not override this method, the status bar style for self is used. If the return value from this method changes, call the setNeedsStatusBarAppearanceUpdate() method."
In other words, if you don't implement solution 3 here, the system will fall back to solution 2 above.
Subclass or extend UINavigationController
class MyNavigationController: UINavigationController {
override var childForStatusBarStyle: UIViewController? {
topViewController
}
}
OR
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
topViewController
}
}
You can return any view controller you'd like above. I recommend one of the following:
topViewController (of UINavigationController) (doc) - The view controller at the top of the navigation stack
visibleViewController (of UINavigationController) (doc) - The view controller associated with the currently visible view in the navigation interface (hint: this can include "a view controller that was presented modally on top of the navigation controller itself")
Note: If you decide to subclass UINavigationController, remember to apply that class to your nav controllers through the identity inspector in IB.
P.S. My code uses Swift 5.1 syntax 😎
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.
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];
}
Currently you can only do light and dark. To change to light do.
Set the UIViewControllerBasedStatusBarAppearance to YES in the .plist file.
In the viewDidLoad method do [self setNeedsStatusBarAppearanceUpdate];
Add the this method:
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
To change it back to dark change the UIStatusBarStyleLightContent to UIStatusBarStyleDefault
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];
}
My App’s background colour is black. Cause the whole view is below the status bar on iOS 7, the content on the status bar will hard to be distinguished. So how to change status bar’s content colour to white?
I've tried preferredStatusBarStyle and several other ways, but failed.
Set "View controller-based status bar appearance” to NO in your info.list file;
Insert
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
to -application:didFinishLaunchingWithOptions: of the AppDelegate.m.
Note: UIStatusBarStyleDefault is the default value for the status bar style, it'll show black content instead. Both UIStatusBarStyleBlackTranslucent & UIStatusBarStyleBlackOpaque are deprecated in iOS 7.0.
UPDATE for iOS 9:
As #ZakariaDarwish mentioned, the method -setStatusBarStyle is deprecated in iOS 9. (Note: The original question was asked for iOS 7 long time ago, and I don't support it now, the new solution below works for me under iOS 9, hence update here.)
So, the only way left (at least for now) is to implement -preferredStatusBarStyle in your view controller (remember to set "View controller-based status bar appearance" back to YES).
You can invoke UIViewController's instance method -setNeedsStatusBarAppearanceUpdate once value changed in -preferredStatusBarStyle or -prefersStatusBarHidden.
There're also two methods -childViewControllerForStatusBarStyle & -childViewControllerForStatusBarHidden to return the preferred style from child view controller as you want.
e.g., if you used below methods
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
to switch status bar style before, you can use code sample below
- (void)shouldChangeStatusBarStyleToLightContent:(BOOL)toLightContent
animated:(BOOL)animated
{
_shouldChangeStatusBarStyleToLightContent = toLightContent;
if (animated) {
[UIView animateWithDuration:.3f animations:^{ [self setNeedsStatusBarAppearanceUpdate]; }];
} else {
[self setNeedsStatusBarAppearanceUpdate];
}
}
- (UIStatusBarStyle)preferredStatusBarStyle
{
return (_shouldChangeStatusBarStyleToLightContent ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault);
}
for this updated solution now.
In your *-Info.plist file:
Set 'View controller-based status bar appearance' to NO
Set 'Status bar style' to UIStatusBarStyleLightContent
Alternatively you can specify Status bar style as 'Black Opaque' or 'Black Translucent' in General tab of the Target.(in Xcode 5.0.1) But they are obsoleted values.
I use this in main controller:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
Place these two keys in info.plist
Here a short and simple solution to set status bar color White
1) First copy this line View controller-based status bar appearance to in your .plist file and set Boolean NO;
2) In your AppDelegate.m file under didFinishLaunchingWithOptions paste this
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:NO];
OR add in .plist
iOS 9 (deprecated warning workaround)
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
#ifdef __IPHONE_7_0
# define STATUS_STYLE UIStatusBarStyleLightContent
#else
# define STATUS_STYLE UIStatusBarStyleBlackTranslucent
#endif
[[UIApplication sharedApplication] setStatusBarStyle:STATUS_STYLE animated:YES];
If your application have different status bar's content color for each view controller the preferred method would be implementing
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
If you need to change the bar's content color globally throughout the application then add following lines of code in your didFinishLaunchingWithOptions method in AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.statusBarStyle = .lightContent
return true
}
Wait setting the statusBarStyle does nothing if your application is using the default UIViewController-based status bar system. For this
Set "View controller-based status bar appearance” to NO in your info.list file
Just a note, since this was there. If you are using a UINavigationController, you can throw this into the view controllers viewDidLoad method:
self.navigationController.navigationBar.barStyle = UIStatusBarStyleLightContent;
To do it programmatically in Swift 3 try this anywhere in your view controller.
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
I also set the plist key "View controller-based status bar appearance" to YES.
I would like to show and hide the Status bar on some controllers. Can this be done or is it more of an overall app setting.
I have seen many posts/questions about the plist update:
View controller-based status bar appearance - NO
If this is completed what control is then given?
I am looking to show the status bar on the main screen of the application. But for example on a side (slide) menu I would like it not to show, is this possible? Can this be changed in IB or code?
EDIT --
I am using a https://github.com/edgecase/ECSlidingViewController implementation.
The main controller (showing the first page) should show the Status bar, but the left menu controller when it slides should not.
I believe the issue is that they both sit within the same root controller (sliding view controller) so it is difficult to complete.
Ideally if the home screen (main page) could take the status bar with it when it slides that would look best.
The plist setting "View controller-based status bar appearance" only controls if a per-controller based setting should be applied on iOS 7.
If you set this plist option to NO, you have to manually enable and disable the status bar like (as it was until iOS 6):
[[UIApplication sharedApplication] setStatusBarHidden:YES]
If you set this plist option to YES, you can add this method to each of your viewControllers to set the statusBar independently for each controller (which is esp. nice if you have a smart subclass system of viewControllers)
- (BOOL)prefersStatusBarHidden {
return YES;
}
Edit:
there are two more methods that are of interest if you are opting in the new viewController-based status bar appearance -
Force a statusbar update with:
[self setNeedsStatusBarAppearanceUpdate]
If you have nested controllers (e.g. a contentViewController in a TabBarController subclass, your TabBarController subclass might ask it's current childViewController and forward this setting. I think in your specific case that might be of use:
- (UIViewController *)childViewControllerForStatusBarHidden {
return _myChildViewController;
}
- (UIViewController *)childViewControllerForStatusBarStyle {
return _myOtherViewController;
}
On iOS 7 and later, just implement -prefersStatusBarHidden, for example in a UIViewController that should hide the status bar:
- (BOOL)prefersStatusBarHidden {
return YES;
}
The default is NO.
Swift 3:
override var prefersStatusBarHidden: Bool {
return true
}
You can also show/hide the status bar in an animation block, by putting animation code inside didSet property of variable that describes whether it should be shown or hidden. When you set a new value for the statusBarHidden Bool, this automatically triggers the animated updating of the status bar over the duration you have chosen.
/// Swift 3 syntax:
var statusBarHidden: Bool = true {
didSet {
UIView.animate(withDuration: 0.5) { () -> Void in
self.setNeedsStatusBarAppearanceUpdate()
}
}
}
override var prefersStatusBarHidden: Bool {
return statusBarHidden
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
statusBarHidden = false // show statusBar, animated, by triggering didSet block
}
Swift version of Mojo66's answer:
override func prefersStatusBarHidden() -> Bool {
return true
}