How to set Status Bar Style in Swift 3
Swift 3 & 4, iOS 10 & 11, Xcode 9 & 10
For me, this method doesn't work:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
when I used to each view controller, but this worked:
In file info.list, add row:
View controller-based status bar appearance
and set toNO
Next in appdelegate:
UIApplication.shared.statusBarStyle = .lightContent
[UPDATED] For Xcode 10+ & Swift 4.2+
This is the preferred method for iOS 7 and higher
In your application's Info.plist
, set View controller-based status bar appearance
to YES
.
Override preferredStatusBarStyle
(Apple docs) in each of your view controllers. For example:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
If you have preferredStatusBarStyle
returning a different preferred status bar style based on something that changes inside of your view controller (for example, whether the scroll position or whether a displayed image is dark), then you will want to call setNeedsStatusBarAppearanceUpdate()
when that state changes.
iOS before version 7, deprecated method
Apple has deprecated this, so it will be removed in the future. Use the above method so that you don't have to rewrite it when the next iOS version is released.
If your application will support In your application's Info.plist
, set View controller-based status bar appearance
to NO
.
In appDelegate.swift
, the didFinishLaunchingWithOptions
function, add:
UIApplication.shared.statusBarStyle = .lightContent
For Navigation Controller
If you use a navigation controller and you want the preferred status bar style of each view controller to be used and set View controller-based status bar appearance
to YES
in your application's info.plist
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
return topViewController?.preferredStatusBarStyle ?? .default
}
}
Latest Update (Xcode 10+ / Swift 4.2+)
This article is left intact for anyone willing to understand the logic behind different approaches that were present for the past several years. Meanwhile, as of Xcode 10, Swift 4.2 first approach is deprecated and is no longer supported (i.e. will not take effect if you try to employ it). It's still referred for your information to better understand the reasoning behind Plist.info
flag and customizing practice.
Important clarification
It is very important to understand two approaches to customizing the status bar appearance. They are different and should not be mixed.
First approach – one color for whole app (DEPRECATED since iOS7)
In info.plist you find or create a key called
View controller-based status bar appearance
and set it to NO.
What it does? It essentially establishes a setting that says that in your application, status bar appearance is not defined individually by each view controller. This is super important to understand. This means that you have uniform setting for entire app, for all screens. There are two settings: default
, which is black text on white background, or lightContent
, which is white text on black background.
To set one of these up (one setting for all screens):
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
application.statusBarStyle = .lightContent // .default
return true
}
This way you won't need to reestablish this setting on each view controller. However, you can always resort to this method to voluntarily change appearance.
Second approach – individual color for each view controller
This is the opposite. To make it work, go ahead to info.plist and set
View controller-based status bar appearance
to YES
This way, whenever a new view controller is open, status bar style is set individually if you insert this implementation in each UIViewController
instance you need:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent // .default
}
You have the same as in first, set either dark or light style for statusbar, individual to each view controller.
This property is fetched by UIKit in two scenarios:
- Upon initialization of the screen, when UI is being prepared.
- Upon calling
setNeedsStatusBarAppearanceUpdate()
in the code.
In latter case, you are eligible to manipulate the statusbar appearance by the following code:
var isDark = false {
didSet {
setNeedsStatusBarAppearanceUpdate()
}
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return isDark ? .lightContent : .default
}
func toggleAppearance() {
isDark.toggle()
}
Then, whenever you call toggleAppearance()
, statusbar style change will be triggered.
Third approach – Hack!
There's a hack which allows to access statusbar directly:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let statusBar = UIApplication.shared.value(forKey: "statusBar") as? UIView {
statusBar.backgroundColor = UIColor.blue
}
return true
}
Why hack? If you need status bar color other than black or white, you use undocumented API. You get statusBar
object using KVC and set its background color. Object you get this way is UIStatusBar
, which is derived from UIView
and thus naturally supports backgroundColor
property. This is dirty, not legal way, but so far it's the only way to set up custom color for statusbar (not taking into account UINavigationBar
approach, which allows to customize navbar+statusbar appearance altogether). It may well lead your app to being rejected. But maybe you're lucky. And if you are, in certain complex circumstances (like hierarchy of nested, child navigation and view controllers) this may be pretty much the only, or at least the less troublesome way to customize statusbar appearance (for example, to make it transparent)
Xcode 10+, Swift 4.2
There are no alternatives any more: developer should let each view controller define statusbar appearance, by setting the flag to YES (or omitting this action, because it's YES by default) and following above instructions.
Bonus
Hack-based solution you might (although not encouraged to) use in complex circumstances in order to voluntarily change statusbar appearance at any stage. Color-wise, the following extension method does exactly what you could have done with regular approach. You can adjust it to your needs.
extension UIViewController {
func setStatusBarStyle(_ style: UIStatusBarStyle) {
if let statusBar = UIApplication.shared.value(forKey: "statusBar") as? UIView {
statusBar.backgroundColor = style == .lightContent ? UIColor.black : .white
statusBar.setValue(style == .lightContent ? UIColor.white : .black, forKey: "foregroundColor")
}
}
}
You could try to override the value returned, rather than setting it. The method is declared as { get }, so just provide a getter:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
If you set this conditionally, you'll need to call setNeedsStatusBarAppearanceUpdate()
so it'll animate the change when you're ready