SwiftUI: Set Status Bar Color For a Specific View
Status bar content color can be modified per view controller based, but SwiftUI uses, most usually, only one view controller, root hosting view controller. So it needs to push that root controller to change preferredStatusBarStyle
property, which in base class is read-only.
So the idea is to override default UIHostingController
to have possibility change that preferredStatusBarStyle
value and use custom Environment
value so any internal SwiftUI subview can modify that preferred content style.
Here is approach, scratchy, (it is assumed that target Info.plist is configured appropriately)
class LocalStatusBarStyle { // style proxy to be stored in Environment
fileprivate var getter: () -> UIStatusBarStyle = { .default }
fileprivate var setter: (UIStatusBarStyle) -> Void = {_ in}
var currentStyle: UIStatusBarStyle {
get { self.getter() }
set { self.setter(newValue) }
}
}
// Custom Environment key, as it is set once, it can be accessed from anywhere
// of SwiftUI view hierarchy
struct LocalStatusBarStyleKey: EnvironmentKey {
static let defaultValue: LocalStatusBarStyle = LocalStatusBarStyle()
}
extension EnvironmentValues { // Environment key path variable
var localStatusBarStyle: LocalStatusBarStyle {
get {
return self[LocalStatusBarStyleKey.self]
}
}
}
// Custom hosting controller that update status bar style
class MyHostingController<Content>: UIHostingController<Content> where Content: View {
private var internalStyle = UIStatusBarStyle.default
@objc override dynamic open var preferredStatusBarStyle: UIStatusBarStyle {
get {
internalStyle
}
set {
internalStyle = newValue
self.setNeedsStatusBarAppearanceUpdate()
}
}
override init(rootView: Content) {
super.init(rootView:rootView)
LocalStatusBarStyleKey.defaultValue.getter = { self.preferredStatusBarStyle }
LocalStatusBarStyleKey.defaultValue.setter = { self.preferredStatusBarStyle = $0 }
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Usage..
- somewhere in scene delegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// ...
window.rootViewController = MyHostingController(rootView: contentView)
- somewhere in content view
struct ContentView: View {
@Environment(\.localStatusBarStyle) var statusBarStyle
...
var body: some View {
ZStack {
....
NavigationView {
NavigationLink(destination: ...) {
...
}
.onAppear {
self.statusBarStyle.currentStyle = .lightContent
}
.onDisappear {
self.statusBarStyle.currentStyle = .default
}
}
}
}
}
SwiftUI setting status bar style
In iOS 14 you just need to change/add 2 keys in Info.plist:
Related Topics
Uitableviewcelldeleteconfirmationcontrol Issue
Want to Create a Cool Static UI But:"Static Table Views Are Only Valid..."
Change Width of a Uibarbuttonitem in a Uinavigationbar
Animating/Moving Views Under Usage of Autolayout
Uiviewcontroller In-Call Status Bar Issue
How to Express Strings in Swift Using Unicode Hexadecimal Values (Utf-16)
Avcapturesession Audio Doesn't Work for Long Videos
Massive Memory Leak in iOS Uiwebview
Alert View Is Showing White Rectangle in iOS7
How to Convert an Uiimage to Grayscale in Swift Using Cifilter
Get the Frame of Uibarbuttonitem in Swift
This Class Is Not Key Value Coding-Compliant for the Key Xxxxxx
Locking a Uisearchbar to the Top of a Uitableview Like Game Center
Application Executable Is Missing a Required Architecture Armv6
Warning: Output of Vertex Shader 'V_Gradient' Not Read by Fragment Shader
How to Get Animated Polyline Route in Gmsmapview, So That It Move Along with Map When Map Is Moved