0

In my project I have two color pickers that change the background color and the font color.

Sheet, where I change the Color:

@ObservedObject var listColor: ListColor

ColorPicker("Hintergrund", selection: $listColor.bgColor)
                               
ColorPicker("Text", selection: $listColor.textColor)

ContentView, where the change should be displayed:

 @ObservedObject private var listColor = ListColor()
 
 VStack{
     VStack{...}
     .backgroundColor(listColor.bgColor)
     .foregroundColor(listColor.textColor)
 }
 .navigationBarTitle(Text("Workout"), displayMode: .automatic)
 .navigationBarColor(backgroundColor: listColor.bgColorNav, titleColor: listColor.textColorNav) // my own viewmodifier
  .navigationBarItems(trailing:
       Button(action: {
             self.showSettings.toggle()
       }) {
             Text("Settings")
                    
       }
       .sheet(isPresented: $showSettings){
            SettingsView(listColor: listColor) //open View with the color pickers
       })

                                    

I also have my own ViewModifer that changes the background color and the font color of the navigation bar.

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
}

func body(content: Content) -> some View {
    ZStack{
        content
        VStack {
            GeometryReader { geometry in
                Color(self.backgroundColor ?? .clear)
                    .frame(height: geometry.safeAreaInsets.top)
                    .edgesIgnoringSafeArea(.top)
                Spacer()
            }
        }
    }
}
}

The problem is that the "normal" background and font color are changed, but not in the navigation bar. I think the problem is that my own ViewModifier for the navbar does not reload the view. I save the colors in the UserDefaults; when I start the app again, the changes are shown in the navigationbar.

Lukas
  • 251
  • 2
  • 13

1 Answers1

1

Instead of using a normal variable inside your ViewModifier, declare a binding to a Color object. Than, if your wrapped value changes, the View (which is in this case the NavigationBar) will automatically redrawn.

My working example:

import SwiftUI

struct NavigationBarModifier: ViewModifier {
    var backgroundColor: Binding<Color>

    init(backgroundColor: Binding<Color>) {
        self.backgroundColor = backgroundColor
    }

    func body(content: Content) -> some View {
        ZStack{
            content
            VStack {
                GeometryReader { geometry in
                    self.backgroundColor.wrappedValue
                        .frame(height: geometry.safeAreaInsets.top)
                        .edgesIgnoringSafeArea(.top)
                    Spacer()
                }
            }
        }
    }
}

extension View {
    func navigationBarColor(_ bgColor: Binding<Color>) -> some View {
        self.modifier(NavigationBarModifier(backgroundColor: bgColor))
    }
}

struct ContentView: View {
    @State private var bgColor = Color(.sRGB, red: 0.98, green: 0.9, blue: 0.2)
    
    var body: some View {
        NavigationView {
            ColorPicker("NavigationBar background color", selection: $bgColor)
                .navigationBarTitle("Title", displayMode: .large)
                .navigationBarColor(self.$bgColor)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Nikolai
  • 659
  • 1
  • 5
  • 10