SwiftUI View and status bar style
In UIKit we can override preferredStatusBarStyle to change the status bar style.
class MyViewController: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
Now when you push another SwiftUI View to NavigationView, there is no way to change the status bar style for the screen you are pushing.
var body: some View {
HStack {
NavigationLink(destination: AnotherScreenView()) {
Text("Push another screen")
}
}
}
A small trick is to always create a new instance of UIHostingController and change statusbar as required.
First create a subclass of UIHostingController that takes statusBarStyle.
class HostingController: UIHostingController<AnyView> {
var statusBarStyle: UIStatusBarStyle
init(rootView: AnyView, statusBarStyle : UIStatusBarStyle = .lightContent) {
self.statusBarStyle = statusBarStyle
super.init(rootView: rootView)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
statusBarStyle
}
}
A small router that holds the UINavigationController, and injected to view hierarchy as an environment object of root view. The only method is push taking a root view and statusBarStyle.
class Router: ObservableObject {
let navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func push(_ view: AnyView, statusBarStyle : UIStatusBarStyle = .lightContent) {
let hostingController = HostingController(rootView: view, statusBarStyle: statusBarStyle:)
self.navigationController.pushViewController(hostingController, animated: true)
}
}
Make a small replacement for SwiftUI's NavigationLink.
struct MyNavigationLink<Destination: View, Content: View>: View {
@EnvironmentObject
var router: Router
let destination: Destination
let viewBuilder: () -> Content
var body: some View {
Button(action: {
self.router.push(AnyView(self.destination), statusBarStyle: .lightContent)
}) {
viewBuilder()
}
}
}
Now usage is simple
var body: some View {
HStack {
MyNavigationLink(destination: AnotherScreenView(), statusBarStyle: .darkContent) {
Text("Push another screen")
}
}
}