0

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

1 Answers1

0

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.