5

Goal: Update Navigation Bar color on press of a button.

Current: NavBar Color doesn't change at all.

Attempted: I am currently using an init() to set the navBarTintColor & I have also tried this answer but neither will update on demand.

Code:

var navColor = Color.green

struct ContentView: View {
    @State var themeColor = Color.green
    @State var items = [0,1,2,3,4,5,6,7,8,9]
    @State var showSheet = false


init() {
    UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.black]
    UINavigationBar.appearance().barTintColor = UIColor(navColor)
    UINavigationBar.appearance().backgroundColor = UIColor(navColor)
}

var body: some View {
    NavigationView{
        List{
            ForEach(0..<items.count){ i in
                Text("Item: \(items[i])")
            }.listRowBackground(themeColor)
        }
        .navigationBarTitle("Theme", displayMode: .inline)
        .navigationBarItems(leading: Button(action: {
            showSheet.toggle()
        }, label: {
            Text("Sheet")
        })
        ,trailing: Button(action: {
            self.themeColor = Color(red: .random(in: 0...1), green: .random(in: 0...1), blue: .random(in: 0...1))
            navColor = Color(red: .random(in: 0...1), green: .random(in: 0...1), blue: .random(in: 0...1))
            items.shuffle()
        }, label: {
            Text("Random Color")
            
        }))
//            .background(NavigationConfigurator { nc in
//                nc.navigationBar.barTintColor = UIColor(navColor)
//                nc.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.black]
//            })
        .sheet(isPresented: $showSheet, content: {
            popSheet()
        })
        
    }
}
}

struct popSheet: View {
var body: some View{
    NavigationView{
        Text("Hello")
            .navigationBarTitle("Sheet", displayMode: .inline)
    }
}
}

Here is the navigation configurator I also attempted to use.

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)
        }
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209
Brenton Beltrami
  • 333
  • 6
  • 11

1 Answers1

11

You can force refresh the NavigationView using .id(themeColor).

Here is a possible solution:

struct ContentView: View {
    @State var themeColor = Color.green
    
    init() {
        updateNavigationBarColor()
    }
    
    var body: some View {
        NavigationView {
            VStack {
                Button("Change to blue") {
                    themeColor = .blue
                    updateNavigationBarColor()
                }
                Button("Change to red") {
                    themeColor = .red
                    updateNavigationBarColor()
                }
            }
            .navigationTitle("Title")
        }
        .id(themeColor)
    }
    
    func updateNavigationBarColor() {
        UINavigationBar.appearance().barTintColor = UIColor(themeColor)
        UINavigationBar.appearance().backgroundColor = UIColor(themeColor)
    }
}
pawello2222
  • 46,897
  • 22
  • 145
  • 209