I am trying to set the status bar style within the latest SwiftUI Lifecycle. Here's my code that performs the logic to do this, adapted from here.
private class HostingController<Content: View>: UIHostingController<Content> {
override var preferredStatusBarStyle: UIStatusBarStyle {
return UIApplication.statusBarStyleHierarchy.last ?? UIApplication.defaultStatusBarStyle
}
}
/// By wrapping views in a StatusBarControllerView, they will become the app's main / primary view.
/// This will enable setting the statusBarStyle.
struct StatusBarControllerView<Content: View>: View {
var content: Content
init(@ViewBuilder content: () -> (Content)) {
self.content = content()
}
var body:some View {
EmptyView()
.onAppear {
UIApplication.shared.setHostingController(rootView: AnyView(content))
}
}
}
extension View {
/// Sets the status bar style color for this view.
func statusBar(style: UIStatusBarStyle) -> some View {
UIApplication.statusBarStyleHierarchy.append(style)
return self
// Once this view appears, set the style to the new style.
.onAppear {
UIApplication.hostingController?.setNeedsStatusBarAppearanceUpdate()
}
// Once it disappears, set it to the previous style.
.onDisappear {
UIApplication.statusBarStyleHierarchy.removeLast()
UIApplication.hostingController?.setNeedsStatusBarAppearanceUpdate()
}
}
}
private extension UIApplication {
static var hostingController: HostingController<AnyView>?
static var statusBarStyleHierarchy: [UIStatusBarStyle] = []
static let defaultStatusBarStyle: UIStatusBarStyle = .lightContent
/// Sets the App to start at rootView
func setHostingController(rootView: AnyView) {
let hostingController = HostingController(rootView: AnyView(rootView))
windows.first?.rootViewController = hostingController
UIApplication.hostingController = hostingController
}
}
I then set up the StatusBarControllerView by placing it in my root App, as shown below:
@main
struct App: SwiftUI.App {
var body: some Scene {
WindowGroup {
StatusBarControllerView {
Text("Content goes here")
}
}
}
}
While it's working great visually, I am now getting the following error in the console:
Unbalanced calls to begin/end appearance transitions for <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x13ee0d9d0>.
Does anyone know how to modify the provided code to avoid this error message? The problem appears to occur when setting the root view controller in private extension UIApplication
:
windows.first?.rootViewController = hostingController
Clarification 1/3/2021
The reason I am trying to change the status bar color this way instead of by editing the plist is because I would like to be able to change the status bar color dynamically in any view of my app, rather than app-wide, as shown below:
struct MyView: View {
var body: some View {
MySubview()
.statusBar(style: .darkContent)
}
}