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

Donovan Smith
  • 261
  • 3
  • 6

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.

Donovan Smith
  • 261
  • 3
  • 6