'How to dynamically change UINavigationBar color in Swiftui
I am working in SwiftUI, and I am trying to get Navigation Bar to update its color when a button is pressed.
I see that there are related questions, but it only allows for static colors in the navigation view.
In the provided example, I only see that the toolbar changes when the tab is changed after the button is pressed.
Is there a way to have the view update without changing tabs (which I believe requires creating a new navigationView).
struct ContentView: View {
var body: some View {
TabView {
First()
.tabItem{
Image(systemName: "1.square")
}
Second()
.tabItem{
Image(systemName: "2.square")
}
Third()
.tabItem{
Image(systemName: "3.square")
}
}
}//:Body
}//:ContentView
struct First: View {
var body: some View {
NavigationView {
HStack {
Button(action: {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = UIColor(.red)
UINavigationBar.appearance().barTintColor = UIColor(.red)
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}, label: {
Text("red")
})//:Button
Button(action: {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = UIColor(.blue)
UINavigationBar.appearance().barTintColor = UIColor(.blue)
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}, label: {
Text("blue")
})//:Button
}
.toolbar(content: {
ToolbarItem(placement: .principal, content: {
Text("Hello World 1")
})
})
}//:NavView
}
}
struct Second: View {
var body: some View {
NavigationView {
ScrollView {
Text("Don't use .appearance()!")
}
.navigationBarTitle("Try it!", displayMode: .inline)
.background(NavigationConfigurator { nc in
nc.navigationBar.barTintColor = .green
nc.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.white]
})
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct NavigationConfigurator: UIViewControllerRepresentable {
var configure: (UINavigationController) -> Void = { _ in }
func makeUIViewController(context: UIViewControllerRepresentableContext<NavigationConfigurator>) -> UIViewController {
UIViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavigationConfigurator>) {
if let nc = uiViewController.navigationController {
self.configure(nc)
}
}
}
struct Third: View {
@State var navigationBackground: UIColor = UIColor(.gray)
var body: some View {
NavigationView {
HStack {
Spacer()
Button(action: {
navigationBackground = UIColor(.purple)
}, label: {
Text("purple")
.foregroundColor(.purple)
})//:Button
Spacer()
Button(action: {
navigationBackground = UIColor(.black)
}, label: {
Text("black")
.foregroundColor(.black)
})//:Button
Spacer()
}
.toolbar(content: {
ToolbarItem(placement: .principal, content: {
Text("Hello World 1")
})
})
}//:NavView
.navigationBarColor(backgroundColor: navigationBackground, titleColor: UIColor(.red))
.navigationBarTitleDisplayMode(.inline)
}
}
struct NavigationBarModifier: ViewModifier {
var backgroundColor: UIColor?
var titleColor: UIColor?
init(backgroundColor: UIColor?, titleColor: UIColor?) {
self.backgroundColor = backgroundColor
let coloredAppearance = UINavigationBarAppearance()
coloredAppearance.configureWithTransparentBackground()
coloredAppearance.backgroundColor = backgroundColor
coloredAppearance.titleTextAttributes = [.foregroundColor: titleColor ?? .white]
coloredAppearance.largeTitleTextAttributes = [.foregroundColor: titleColor ?? .white]
UINavigationBar.appearance().standardAppearance = coloredAppearance
UINavigationBar.appearance().compactAppearance = coloredAppearance
UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
UIToolbar.appearance().barTintColor = backgroundColor
}
func body(content: Content) -> some View {
ZStack{
content
VStack {
GeometryReader { geometry in
Color(self.backgroundColor ?? .clear)
.frame(height: geometry.safeAreaInsets.top)
.edgesIgnoringSafeArea(.top)
Spacer()
}
}
}
}
}
extension View {
func navigationBarColor(backgroundColor: UIColor?, titleColor: UIColor?) -> some View {
self.modifier(NavigationBarModifier(backgroundColor: backgroundColor, titleColor: titleColor))
}
}
The solutions that I tried are derivatives of answers from this post: SwiftUI update navigation bar title color
Solution 1:[1]
I just found a solution much later here SwiftUI: Update Navigation Bar Color
The thing that seems to make everything work to force the change is an id property on the navigation view.
This worked for my use case.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
