NavigationView dynamic background color in SwiftUI

SwiftUI Dynamic NavigationBar Color
SwiftUI Dynamic NavigationBar Color

As you may noticed, customizing navigation bar using only SwiftUI standard NavigationView is not possible in the first release of SwiftUI (as of Xcode 11), as no API is provided to change the background color. More over you as you don't have access to NavigationBarController is really hard to achieve any customization.

In this article, I will show you how to compose your view to get the intended behavior.

Solution

Where are going to create custom modifier so we can change the color of NavBar on every view. The usage will be then as follow

struct SomeView: View {
 
    var body: some View {
        NavigationView {
              Text("Hello World")
            }
            .navigationBarColor(.green) // This is how you will use it
        }
    }

}

An here is implementation. Fist of all we will create our modifier:

struct NavigationBarModifier: ViewModifier {
        
    var backgroundColor: UIColor?
    
    init( backgroundColor: UIColor?) {
        self.backgroundColor = backgroundColor
        let coloredAppearance = UINavigationBarAppearance()
        coloredAppearance.configureWithTransparentBackground()
        coloredAppearance.backgroundColor = .clear
        coloredAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        coloredAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        
        UINavigationBar.appearance().standardAppearance = coloredAppearance
        UINavigationBar.appearance().compactAppearance = coloredAppearance
        UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
        UINavigationBar.appearance().tintColor = .white

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

And then we will extend the view so we can use it anywhere in SwiftUI scope.

extension View {
 
    func navigationBarColor(_ backgroundColor: UIColor?) -> some View {
        self.modifier(NavigationBarModifier(backgroundColor: backgroundColor))
    }

}

SwiftUI Elements

You can find also the whole implementation in my opensource UI kit.

References