Updating the status bar style between view controllers
There is a great deal of misunderstanding promulgated about how to govern the status bar style when your view controller is a child of a navigation controller.
Your child view controllers can implement preferredStatusBarStyle
, and this will work correctly if the navigation bar is hidden.
If the navigation bar is showing, the navigation controller sets the status bar style based on the navigation bar's barStyle
— to .default
if the bar style is .default
, and to .lightContent
if the bar style is .black
. So the correct way for your view controller to set the status bar style, when the navigation bar is showing, is to set the navigation controller's navigation bar style.
The obvious place to do this is in viewWillAppear
, which is called whenever this view controller becomes the top of the navigation controller's stack:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.barStyle = .black // or .default
}
Preferred status bar style of view controller is ignored when in navigation controller
When you're in a navigation controller that will not get called. The navigation controller's preferredStatusBarStyle will be called. Try this along with your code:
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
}
How do I prevent iOS 13's Dark Mode from changing the text color in my app's status bar?
iOS 13 Solution(s)
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:
Opt out of Dark Mode entirely
- In your
info.plist
, add the following property:- Key -
UIUserInterfaceStyle
(aka. "User Interface Style") - Value - Light
- Key -
- In your
Override
preferredStatusBarStyle
withinUINavigationController
preferredStatusBarStyle
(doc) - The preferred status bar style for the view controllerSubclass
or extendUINavigationController
class MyNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}ORextension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
Override
childForStatusBarStyle
withinUINavigationController
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 extendUINavigationController
class MyNavigationController: UINavigationController {
override var childForStatusBarStyle: UIViewController? {
topViewController
}
}ORextension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
topViewController
}
}You can return any view controller you'd like above. I recommend one of the following:
topViewController
(ofUINavigationController
) (doc) - The view controller at the top of the navigation stackvisibleViewController
(ofUINavigationController
) (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.
Edits: Strikethrough edits were made to remove extensions as a suggested answer. Other developers noted that they stopped working in Xcode 11.4 and Apple's documentation discourages the use of this ambiguous behavior.
P.S. My code uses Swift 5.1 syntax /p>
Changing the Status Bar Color for specific ViewControllers using Swift in iOS8
After reading all the suggestions, and trying out a few things, I could get this to work for specific viewcontrollers using the following steps :
First Step:
Open your info.plist and insert a new key named "View controller-based status bar appearance" to NO
Second Step (Just an explanation, no need to implement this):
Normally we put the following code in the application(_:didFinishLaunchingWithOptions:)
method of the AppDelegate,
Swift 2
UIApplication.sharedApplication().statusBarStyle = .LightContent
Swift 3
UIApplication.shared.statusBarStyle = .lightContent
but that affects the statusBarStyle
of all the ViewControllers.
So, how to get this working for specific ViewControllers - Final Step:
Open the viewcontroller file where you want to change the statusBarStyle
and put the following code in viewWillAppear()
,
Swift 2
UIApplication.sharedApplication().statusBarStyle = .LightContent
Swift 3
UIApplication.shared.statusBarStyle = .lightContent
Also, implement the viewWillDisappear()
method for that specific viewController and put the following lines of code,
Swift 2
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.Default
}
Swift 3
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
UIApplication.shared.statusBarStyle = UIStatusBarStyle.default
}
This step will first change the statusBarStyle
for the specific viewcontroller and then change it back to default
when the specific viewcontroller disappears. Not implementing the viewWillDisappear()
will change the statusBarStyle
permanently to the new defined value of UIStatusBarStyle.LightContent
UIStatusBarStyle PreferredStatusBarStyle does not work on iOS 7
OK, here's the trick. You do have to add the key "View controller-based status bar" and set the value to No.
This is counter to what it appears the meaning of this key is, but even if you set the value to No
, you can still change the appearance of the status bar, and whether it shows or not in any view controller. So it acts like "Yes" but set it to "No"!
Now I can get the status bar white or dark.
How to change Status Bar text color in iOS
Set the
UIViewControllerBasedStatusBarAppearance
toYES
in the .plist file.In the
viewDidLoad
do a[self setNeedsStatusBarAppearanceUpdate];
Add the following method:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
Note: This does not work for controllers inside UINavigationController
, please see Tyson's comment below :)
Swift 3 - This will work controllers inside UINavigationController
. Add this code inside your controller.
// Preferred status bar style lightContent to use on dark background.
// Swift 3
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
Swift 5 and SwiftUI
For SwiftUI create a new swift file called HostingController.swift
import Foundation
import UIKit
import SwiftUI
class HostingController: UIHostingController<ContentView> {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
Then change the following lines of code in the SceneDelegate.swift
window.rootViewController = UIHostingController(rootView: ContentView())
to
window.rootViewController = HostingController(rootView: ContentView())
Related Topics
Swift Uiview Opacity Programmatically
Initialization of 'Unsafepointer<Int>' Results in a Dangling Pointer
Uibarbuttonitem Changing Title Not Working
iOS 14 Pickerview Cutting Off Text
How to Fix Broken Transform-Origin on iOS11 and Macos10.12 Safari
App Crashes After Updating Coredata Model That Is Being Displayed in a UItableview
iOS - Running Background Task for Update User Location Using Swift
Add a UIbutton as a Subview to a UItabbar
How to Handle a File Sent with 'Open In...' from Another App to My Own iOS App
Fixing Low Fps in Swift Playground
Replacement for Arkit in iOS10
Get Xcode 5 to Warn About New API Calls
How to Get a Low Res Image, or Thumbnail from the Alassetrepresentation in Swift
How to Make One Side of a Div Pointy with CSS
iOS App Breakpoints on Running