2

I know I can globally change the navigation bar using init:

init() {
    UINavigationBar.appearance().largeTitleTextAttributes = [
        .foregroundColor: UIColor.red
    ]
}

How would I do this for the current view only? I only want to set the navigation title color for the current view, not all views of the app.

kdion4891
  • 1,169
  • 12
  • 17

3 Answers3

2

The simplest case is as follows (you can also store/restore previous settings in some local var):

var body: some View {
    NavigationView(){
        List {
            // Some content is here
        }
        .navigationBarTitle("Title")
        .onAppear(perform: {
            UINavigationBar.appearance().largeTitleTextAttributes = [
                .foregroundColor: UIColor.red
            ]
        })
        .onDisappear(perform: {
            UINavigationBar.appearance().largeTitleTextAttributes = nil
        })

    }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
0

Not sure do you have this issue now.

I have searched for this issue and find a great article about this, you could wrap the settings of navigation bar style as a view modifier.

Check this Link.

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()
                }
            }
        }
    }
}

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

}

After that, apply like this:

.navigationBarColor(backgroundColor: .clear, titleColor: .white)
Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
Phillip
  • 801
  • 10
  • 13
0

Here's a solution that sets attributes when a child view is shown, and resets them when the child view disappears:

import SwiftUI

struct ExampleView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: NestedView()) {
                Label("Navigate", systemImage: "folder")
            }
            .navigationTitle("Home")
        }
        // This is important, it doesn't work without it.
        .navigationViewStyle(.stack)
    }
}

struct NestedView: View {
    var body: some View {
        ZStack {
            NavigationControllerAccessor(viewWillAppear: { nav in
                nav.navigationBar.largeTitleTextAttributes = [
                    .foregroundColor: UIColor.red
                ]
            }, viewWillDisappear: { nav in
                nav.navigationBar.largeTitleTextAttributes = nil
            })
            Text("In nested view")
        }
        .navigationTitle("Nested")
    }
}

struct NavigationControllerAccessor: UIViewControllerRepresentable {
    var viewWillAppear: (UINavigationController) -> Void
    var viewWillDisappear: ((UINavigationController) -> Void)? = nil

    private let proxyController = ViewController()

    func makeUIViewController(context: UIViewControllerRepresentableContext<NavigationControllerAccessor>) -> UIViewController {
        proxyController.viewWillAppearCallback = viewWillAppear
        if let viewWillDisappear = viewWillDisappear {
            proxyController.viewWillDisappearCallback = viewWillDisappear
        }
        return proxyController
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavigationControllerAccessor>) {}

    private class ViewController: UIViewController {
        var viewWillAppearCallback: (UINavigationController) -> Void = { _ in }
        var viewWillDisappearCallback: (UINavigationController) -> Void = { _ in }

        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            if let nav = navigationController {
                viewWillAppearCallback(nav)
            }
        }

        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            if let nav = navigationController {
                viewWillDisappearCallback(nav)
            }
        }
    }
}

struct ExampleView_Previews: PreviewProvider {
    static var previews: some View {
        ExampleView()
    }
}

Demo:

Screen recording of example

robinst
  • 30,027
  • 10
  • 102
  • 108