SwiftUI обновляет цвет заголовка панели навигации

Как изменить цвет заголовка панели навигации в SwiftUI

NavigationView {
            List{
                ForEach(0..<15) { item in
                    HStack {
                        Text("Apple")
                            .font(.headline)
                            .fontWeight(.medium)
                            .color(.orange)
                            .lineLimit(1)
                            .multilineTextAlignment(.center)
                            .padding(.leading)
                            .frame(width: 125, height: nil)


                        Text("Apple Infinite Loop. Address: One Infinite Loop Cupertino, CA 95014 (408) 606-5775 ")
                            .font(.subheadline)
                            .fontWeight(.regular)
                            .multilineTextAlignment(.leading)
                            .lineLimit(nil)


                    }
                }
            }
            .navigationBarTitle(Text("TEST")).navigationBarHidden(false).foregroundColor(.orange)
            }

Я пробовал с .foregroundColor(.orange) Но это не работает

также пытался .navigationBarTitle(Text("TEST").color(.orange))

Любая помощь?

30 ответов

Это не нужно использовать.appearance() сделать это глобально.

Хотя SwiftUI не предоставляет напрямую стили навигации, вы можете обойти это, используя UIViewControllerRepresentable. Поскольку SwiftUI использует обычныйUINavigationController за кулисами контроллер представления по-прежнему будет иметь действующий .navigationController свойство.

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 ContentView: View {
    var body: some View {
        NavigationView {
            ScrollView {
                Text("Don't use .appearance()!")
            }
            .navigationBarTitle("Try it!", displayMode: .inline)
            .background(NavigationConfigurator { nc in
                nc.navigationBar.barTintColor = .blue
                nc.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.white]
            })
        }
    .navigationViewStyle(StackNavigationViewStyle())
    }
}

В SwiftUI вы не можете напрямую изменить навигационный заголовок. Вы должны изменить внешний вид UINavigation в init() нравится,

struct YourView: View {

    init() {
        //Use this if NavigationBarTitle is with Large Font
        UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: UIColor.red]

        //Use this if NavigationBarTitle is with displayMode = .inline
        UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.red]
    }

    var body: some View {

        NavigationView {
            List{
                ForEach(0..<15) { item in
                    HStack {
                        Text("Apple")
                            .font(.headline)
                            .fontWeight(.medium)
                            .color(.orange)
                            .lineLimit(1)
                            .multilineTextAlignment(.center)
                            .padding(.leading)
                            .frame(width: 125, height: nil)


                        Text("Apple Infinite Loop. Address: One Infinite Loop Cupertino, CA 95014 (408) 606-5775 ")
                            .font(.subheadline)
                            .fontWeight(.regular)
                            .multilineTextAlignment(.leading)
                            .lineLimit(nil)
                    }
                }
            }
            .navigationBarTitle(Text("TEST")).navigationBarHidden(false)
            //.navigationBarTitle (Text("TEST"), displayMode: .inline)
        }
    }
}

Я надеюсь, что это сработает. Спасибо!!

Я искал эту проблему и нашел отличную статью об этом, вы можете обернуть настройки стиля панели навигации в качестве модификатора представления.

Проверить эту ссылку.

Примечания: я считаю, что вам нужно обновить код в этом примере, добавить titleColor параметр.

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

}

После этого примените так:

.navigationBarColor(backgroundColor: .clear, titleColor: .white)

Надеюсь, это сработает.

В iOS 14 в SwiftUI есть возможность настроить панель навигации с помощью нового toolbar модификатор.

Нам нужно установить ToolbarItem типа размещения .principal к новому toolbarмодификатор. Вы даже можете установить изображение и многое другое.

NavigationView {
    Text("My View!")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .principal) {
                HStack {
                    Image(systemName: "sun.min.fill")
                    Text("Title")
                        .font(.headline)
                        .foregroundColor(.orange)
                }
            }
        }
}

Опираясь на ответ Арсения, я обнаружил, что элегантный способ заставить его работать согласованно - создать подкласс UIViewController и выполните настройку в viewDidLayoutSubviews().

Применение:

VStack {
    Text("Hello world")
        .configureNavigationBar {
            $0.navigationBar.setBackgroundImage(UIImage(), for: .default)
            $0.navigationBar.shadowImage = UIImage()
        }
}

Реализация:

extension View {
    func configureNavigationBar(configure: @escaping (UINavigationController) -> Void) -> some View {
        modifier(NavigationConfigurationViewModifier(configure: configure))
    }
}

struct NavigationConfigurationViewModifier: ViewModifier {
    let configure: (UINavigationController) -> Void

    func body(content: Content) -> some View {
        content.background(NavigationConfigurator(configure: configure))
    }
}

struct NavigationConfigurator: UIViewControllerRepresentable {
    let configure: (UINavigationController) -> Void

    func makeUIViewController(
        context: UIViewControllerRepresentableContext<NavigationConfigurator>
    ) -> NavigationConfigurationViewController {
        NavigationConfigurationViewController(configure: configure)
    }

    func updateUIViewController(
        _ uiViewController: NavigationConfigurationViewController,
        context: UIViewControllerRepresentableContext<NavigationConfigurator>
    ) { }
}

final class NavigationConfigurationViewController: UIViewController {
    let configure: (UINavigationController) -> Void

    init(configure: @escaping (UINavigationController) -> Void) {
        self.configure = configure
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        if let navigationController = navigationController {
            configure(navigationController)
        }
    }
}

Я использовал несколько иной подход; Я хотел изменить только цвет текста заголовка, и ничего больше о NavigationBar. Используя вышеизложенное и это в качестве вдохновения, я остановился на:

      /// Sets the text color for a navigation bar title.
/// - Parameter color: Color the title should be
///
/// Supports both regular and large titles.
@available(iOS 14, *)
func navigationBarTitleTextColor(_ color: Color) -> some View {
    let uiColor = UIColor(color)
    
    // Set appearance for both normal and large sizes.
    UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: uiColor ]
    UINavigationBar.appearance().largeTitleTextAttributes = [.foregroundColor: uiColor ]
    
    return self
}

Для этого требуется iOS 14, потому что UIColor.init(_ color: Color) требуется iOS 14.

Что может быть использовано как таковое:

      struct ExampleView: View {
    var body: some View {
        NavigationView {
            Text("Hello, World!")
                .navigationBarTitle("Example")
                .navigationBarTitleTextColor(Color.red)
        }
    }
}

Что, в свою очередь, дает:

начиная с iOS 14, вы можете иметь любой пользовательский вид, который вы хотите (включая пользовательский текст с собственным цветом и шрифтом)

      .navigationBarTitleDisplayMode(.inline)
.toolbar {
    ToolbarItem(placement: .principal) {
        VStack {
            Text("Yellow And Bold Title")
                .bold()
                .foregroundColor(.yellow)
        }
    }
}

Также вы можете установить цвет панели навигации из iOS 16 , например:

      .toolbarBackground(.red, for: .navigationBar)

Вместо того, чтобы устанавливать appearance(), который влияет на все панели навигации, вы можете настроить их индивидуально с помощью SwiftUI-Introspect.

Пример:

      struct ContentView: View {
    var body: some View {
        NavigationView {
            ScrollView {
                Text("Hello world!")
            }
            .navigationTitle("Title")
        }
        .introspectNavigationController { nav in
            nav.navigationBar.barTintColor = .systemBlue
        }
    }
}

Результат:

Используйте код ниже для настройки цвета в SwiftUI

Это для основного цвета фона корпуса:-

struct ContentView: View {

var body: some View {

 Color.red
.edgesIgnoringSafeArea(.all)

 }

}

Для панели навигации:-

struct ContentView: View {

@State var msg = "Hello SwiftUI"

init() {

    UINavigationBar.appearance().backgroundColor = .systemPink

     UINavigationBar.appearance().largeTitleTextAttributes = [
        .foregroundColor: UIColor.white,
               .font : UIFont(name:"Helvetica Neue", size: 40)!]

}

var body: some View {

    NavigationView {

    Text(msg)

        .navigationBarTitle(Text("NAVIGATION BAR"))

    }

    }

  }

Для других элементов пользовательского интерфейса Настройка цвета

struct ContentView: View {

@State var msg = "Hello SwiftUI"

var body: some View {

        Text(msg).padding()
            .foregroundColor(.white)
            .background(Color.pink)

    }
 }

Я разработал небольшой пример пользовательской навигации SwiftUI, которая может обеспечить полную визуальную настройку и программную навигацию. Он может быть использован в качестве замены для NavigationView.

Вот класс NavigationStack, который имеет дело с currentView и стеком навигации:

final class NavigationStack: ObservableObject  {
    @Published var viewStack: [NavigationItem] = []
    @Published var currentView: NavigationItem

    init(_ currentView: NavigationItem ){
        self.currentView = currentView
    }

    func unwind(){
        if viewStack.count == 0{
            return
        }

        let last = viewStack.count - 1
        currentView = viewStack[last]
        viewStack.remove(at: last)
    }

    func advance(_ view:NavigationItem){
        viewStack.append( currentView)
        currentView = view
    }

    func home( ){
        currentView = NavigationItem( view: AnyView(HomeView()))
        viewStack.removeAll()
    }
}

Вы можете посмотреть здесь: полный пример с объяснением:

PS: я не уверен, почему этот был удален. Я думаю, что это ответ на вопрос, поскольку это идеальная функциональная альтернатива NavigationView.

На основе этого /questions/49907226/swiftui-obnovlyaet-tsvet-zagolovka-paneli-navigatsii/57168432#57168432 я создал расширение, в котором вы можете одновременно установить цвет фона и цвет заголовка.

      import SwiftUI

extension View {
    
    /// Sets background color and title color for UINavigationBar.
    @available(iOS 14, *)
    func navigationBar(backgroundColor: Color, titleColor: Color) -> some View {
        let appearance = UINavigationBarAppearance()
        appearance.configureWithTransparentBackground()
        appearance.backgroundColor = UIColor(backgroundColor)

        let uiTitleColor = UIColor(titleColor)
        appearance.largeTitleTextAttributes = [.foregroundColor: uiTitleColor]
        appearance.titleTextAttributes = [.foregroundColor: uiTitleColor]

        UINavigationBar.appearance().standardAppearance = appearance
        UINavigationBar.appearance().scrollEdgeAppearance = appearance
        
        return self
    }
}

Вот как это использовать:

      var body: some View {
    NavigationView {
        Text("Hello world!") // This could be any View (List, VStack, etc.)
        .navigationTitle("Your title here")
        .navigationBar(backgroundColor: .blue, titleColor: .white)
    }
}

Удачного кодирования!

init() { // for navigation bar title color
        UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.red]
// For navigation bar background color 
UINavigationBar.appearance().backgroundColor = .green
   }     
NavigationView {
            List{
                ForEach(0..<15) { item in
                    HStack {
                        Text("Apple")
                            .font(.headline)
                            .fontWeight(.medium)
                            .color(.orange)
                            .lineLimit(1)
                            .multilineTextAlignment(.center)
                            .padding(.leading)
                            .frame(width: 125, height: nil)


                        Text("Apple Infinite Loop. Address: One Infinite Loop Cupertino, CA 95014 (408) 606-5775 ")
                            .font(.subheadline)
                            .fontWeight(.regular)
                            .multilineTextAlignment(.leading)
                            .lineLimit(nil)


                    }
                }
            }
            .navigationBarTitle(Text("TEST")).navigationBarHidden(false)
            }

Если у вас есть контент как

struct MyContent : View {
...
}

тогда вы можете поместить это в виде навигации с красным фоном:

NavigationView {
    ZStack(alignment: .top) {
        Rectangle()
            .foregroundColor(Color.red)
            .edgesIgnoringSafeArea(.top)
        MyContent()
    }
}

Я обновлю свой ответ, как только узнаю, как обновить сам текст заголовка.

Определенно уже есть несколько хороших ответов, но все они охватывают только часть работы:

  1. Отличное решение от @arsenius - дайте хорошее начало

  2. Элегантный способ от @EngageTheWarpDrive - это определенно улучшает юзабилити

  3. Для последней версии iOS и swiftUI @Thahir предлагает использовать панель инструментов

Еще несколько предложений предлагают использовать UIAppearence глобальная конфигурация для UINavigationBar - как по мне, глобальные изменения - не лучшая идея и не всегда подходит.

В итоге я объединил все предложения в следующий код:

  1. Создайте NavigationControllerRepresentable и modifier за navigationBar конфигурация:

     struct NavigationControllerLayout: UIViewControllerRepresentable {
    
         var configure: (UINavigationController) -> () = { _ in }
    
         func makeUIViewController(
             context: UIViewControllerRepresentableContext<NavigationControllerLayout>
         ) -> UIViewController {
             UIViewController()
         }
    
         func updateUIViewController(
             _ uiViewController: UIViewController,
             context: UIViewControllerRepresentableContext<NavigationControllerLayout>
         ) {
             if let navigationContoller = uiViewController.navigationController {
                 configure(navigationContoller)
             }
         }
     }
    
     extension View {
    
         func configureNavigationBar(_ configure: @escaping (UINavigationBar) -> ()) -> some View {
             modifier(NavigationConfigurationViewModifier(configure: configure))
         }
     }
    
     struct NavigationConfigurationViewModifier: ViewModifier {
    
         let configure: (UINavigationBar) -> ()
    
         func body(content: Content) -> some View {
             content.background(NavigationControllerLayout(configure: {
                 configure($0.navigationBar)
             }))
         }
     }
    
  2. Модифицировать navigationBar чтобы удовлетворить ваши требования (например, цвет bg и другие реквизиты):

    extension UINavigationBar {
    
         enum Appearence {
    
             case transparent
             case defaultLight
             case colored(UIColor?)
    
             var color: UIColor {
                 ...
             }
    
             var appearenceColor: UIColor {
                 ...
             }
    
             var tint: UIColor {
                 ....
             }
    
             var effect: UIBlurEffect? {
                ....
             }
         }
    
         func switchToAppearence(_ type: Appearence) {
             backgroundColor = type.color
             barTintColor = type.tint
    
             // for iOS 13+
             standardAppearance.backgroundColor = type.appearenceColor
             standardAppearance.backgroundEffect = type.effect
    
             // u can use other properties from navBar also simply modifying this function
         }
     }
    
  3. Как видите, здесь нам определенно нужен мост между Color и UIColor. Начиная с iOS 14 - ты можешь просто UIColor.init(_ color: Color), но прежде iOS 14 такого способа нет, поэтому я пришел к простому решению:

     extension Color {
    
         /// Returns a `UIColor` that represents this color if one can be constructed
         ///
         /// Note: Does not support dynamic colors
         var uiColor: UIColor? {
             self.cgColor.map({ UIColor(cgColor: $0) })
         }
     }
    

это не сработает для динамических цветов

  1. В результате вы можете использовать это следующим образом:

     // modifier to `NavigationView`
     .configureNavigationBar {
         $0.switchToAppearence(.defaultLight)
     }
    

Надеюсь, это может кому-то помочь;)

обновление для 13.4

примечание: вернувшись к этому на следующий день, возможно, некоторые из моих проблем были вызваны моей несколько нестандартной настройкой: я все еще использую mojave, но вручную добавил файлы поддержки 13.4 (обычно доступны только через xcode 11.4, для чего требуется catalina). Я упоминаю об этом, потому что у меня / были некоторые проблемы с настраиваемым цветом панели вкладок, но я только заметил, что они проявляются только тогда, когда у меня действительно есть телефон, и я запускаю приложение из xcode. если я отключаюсь и просто запускаю приложение в обычном режиме, я не вижу проблем с панелью вкладок, поэтому возможно, что проблема с навигационной панелью имела некоторое сходство...

(я бы добавил это как комментарий к ответу Арсения (принятому в настоящее время) выше, но у меня нет представителя, так что...)

Я использовал это решение, и оно отлично работало до 13.4, что, похоже, сломало его, по крайней мере, для меня. после большого количества трассировок иерархии представлений, похоже, что они изменили ситуацию, так что неявный UINavigationController больше не является легко доступным через переданный UIViewController, как описано в обходном пути. он все еще там (довольно далеко вверху по дереву), нам просто нужно его найти.

с этой целью мы можем просто пройтись по иерархии представлений, пока не найдем панель навигации, а затем, как обычно, установить на ней желаемые параметры. это требует новой функции обнаружения и некоторых незначительных изменений в структуре NavigationConfigurator и ее создании...

во-первых, функция обнаружения:

func find_navbar(_ root: UIView?) -> UINavigationBar?
{
    guard root != nil else { return nil }

    var navbar: UINavigationBar? = nil
    for v in root!.subviews
    {   if type(of: v) == UINavigationBar.self { navbar = (v as! UINavigationBar); break }
        else { navbar = find_navbar(v); if navbar != nil { break } }
    }

    return navbar
}

измените NavigationConfigurator следующим образом (обратите внимание, что мы больше не заботимся о передаче представления, поскольку оно больше не является надежным):

struct NavigationConfigurator: UIViewControllerRepresentable
{
    @EnvironmentObject var prefs: Prefs     // to pick up colorscheme changes

    var configure: () -> Void = {}
    func makeUIViewController(context: UIViewControllerRepresentableContext<NavigationConfigurator>) -> UIViewController { UIViewController() }
    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<NavigationConfigurator>) { self.configure() }
}

(в моем приложении у меня есть объект Prefs, который отслеживает цвета и т. д.)

... затем на сайте создания экземпляра сделайте что-то вроде этого:

MyView()
    .navigationBarTitle("List", displayMode: .inline)
    .navigationBarItems(trailing: navbuttons)
    .background(NavigationConfigurator {
        if self.prefs.UI_COLORSCHEME != Colorscheme.system.rawValue
        {   if let navbar = find_navbar(root_vc?.view)
            {   navbar.barTintColor = Colors.uicolor(.navbar, .background)
                navbar.backgroundColor = .black
                navbar.titleTextAttributes = [.foregroundColor: Colors.uicolor(.navbar, .foreground)]
                navbar.tintColor = Colors.uicolor(.navbar, .foreground)
            }
        }
    })

обратите внимание, что я захватываю контроллер корневого представления в другом месте своего приложения и использую его здесь для перехода к find_navbar(). возможно, вы захотите сделать это по-другому, но у меня уже есть эта переменная по другим причинам... там есть еще кое-что, специфичное для моего приложения, например, объекты, связанные с цветом, но вы поняли идею.

Я до сих пор не понял, как сделать цвет переднего плана для каждого просмотра, но я нашел простой обходной путь для цвета фона.

При использовании .inline название, вы можете просто использовать VStack с прямоугольником вверху NavigationView:

NavigationView {
    VStack() {
        Rectangle()
            .foregroundColor(.red)
            .edgesIgnoringSafeArea(.top)
            .frame(height: 0)

        List {
            Text("Hello World")
            Text("Hello World")
            Text("Hello World")
        }
    }
    .navigationBarTitle("Hello World", displayMode: .inline)
    // ...

Обратите внимание, как прямоугольник использует высоту кадра 0 а также .edgesIgnoringSafeArea(.top).

.foregroundColor(.orange) - изменяет внутренние представления NavigationView.

Но чтобы изменить сам вид навигации, вам нужно использовать UINavigationBar Appearance() в init()

Я искал эту проблему и нашел отличную статью об этом . Я изменил ваш код этой статьей и добился успеха. Вот как я решаю эту проблему:

      struct ContentView: View {
    
    init() {
        let coloredAppearance = UINavigationBarAppearance()
        
        // this overrides everything you have set up earlier.
        coloredAppearance.configureWithTransparentBackground()
        coloredAppearance.backgroundColor = .green
        coloredAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.black]
        
        // to make everything work normally
        UINavigationBar.appearance().standardAppearance = coloredAppearance
        UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
    }
    
    var body: some View {
        NavigationView {
            List{
                ForEach(0..<15) { item in
                    HStack {
                        Text("Apple")
                            .font(.headline)
                            .fontWeight(.medium)
                            .lineLimit(1)
                            .multilineTextAlignment(.center)
                            .padding(.leading)
                            .frame(width: 125, height: nil)
                            .foregroundColor(.orange)
                        
                        
                        Text("Apple Infinite Loop. Address: One Infinite Loop Cupertino, CA 95014 (408) 606-5775 ")
                            .font(.subheadline)
                            .fontWeight(.regular)
                            .multilineTextAlignment(.leading)
                            .lineLimit(nil)
                            .foregroundColor(.orange)
                    }
                }
            }
            .navigationBarTitle(Text("TEST"))
        }
// do not forget to add this
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

Вы также можете взять несколько примеровздесь

Цвет заголовка навигации WatchOS с использованием SwiftUI
Примечание для watchOS заключается в том, что вам не нужно возиться с цветом навигации. Это цвет часового акцента, который вам нужно изменить. В вашем проекте перейдите в WatchProjectName->Asset->Accent и измените это

https://developer.apple.com/documentation/watchkit/setting_the_app_s_tint_color

Вот решение, которое сработало для меня. Вам нужно начать с UINavigationController в качестве rootViewController.

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        let nav = setupNavigationController()
        window.rootViewController = nav
        self.window = window
        window.makeKeyAndVisible()
    }
}

func setupNavigationController() -> UINavigationController {
    let contentView = ContentView()
    let hosting = UIHostingController(rootView: contentView)
    let nav = NavigationController(rootViewController: hosting)
    let navBarAppearance = UINavigationBarAppearance()
    navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
    navBarAppearance.backgroundColor = UIColor.black
    nav.navigationBar.standardAppearance = navBarAppearance
    nav.navigationBar.scrollEdgeAppearance = navBarAppearance
    nav.navigationBar.prefersLargeTitles = true
    return nav
}

а затем в вашем просмотре содержимого:

struct ContentView: View {

    @State private var isModalViewPresented: Bool = false

    var body: some View {
        List(0 ..< 10, rowContent: { (index) in
            NavigationLink(destination: DetailView()) {
                Text("\(index)")
            }
        })
        .navigationBarItems(trailing: Button("Model") {
            self.isModalViewPresented.toggle()
        })
        .sheet(isPresented: $isModalViewPresented, content: {
            ModalView()
        })
        .navigationBarTitle("Main View")
    }
}

и если вы хотите изменить цвет в какой-то момент, например, в модальном представлении, используйте ответ, приведенный здесь

struct ModalView: View {
    var body: some View {
        NavigationView {
           Text("Hello, World!")
           .navigationBarTitle("Modal View")
           .background(NavigationConfigurator { nc in
              nc.navigationBar.backgroundColor = UIColor.blue
              nc.navigationBar.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
           })
       }
    }
}

вы можете создать подкласс UINavigationController, чтобы изменить цвет строки состояния

class NavigationController: UINavigationController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override var preferredStatusBarStyle: UIStatusBarStyle 
    {
        .lightContent
    }
}

Начиная с iOS 16+, вы можете использовать комбинацию модификаторовtoolbarBackground иtoolbarColorScheme , чтобы добиться определенного уровня настройки панели навигации.

      NavigationStack {
    ContentView()
        .toolbarBackground(Color.accentColor)
        .toolbarBackground(.visible)
        .toolbarColorScheme(.dark)
}

Отдайте должное, я узнал об этом от Сарунва .

раздражает использованиеNavigationView. С iOS 16. Вместо использованияNavigationTitle, вы можете использовать.toolbarчтобы настроить заголовок, это было бы более гибко.

Например:

      import SwiftUI

struct Company: Identifiable, Hashable {
    let id = UUID()
    let name: String
}

struct ContentView: View {
    private let companies: [Company] = [
        .init(name: "Google"),
        .init(name: "Apple"),
        .init(name: "Amazon"),
        .init(name: "Huawei"),
        .init(name: "Baidu")
    ]
    
    @State private var path: [Company] = []
    var body: some View {
        NavigationStack(path: $path) {
            List(companies) { company in
                NavigationLink(company.name, value: company)
            }
            .toolbar {
                    ToolbarItem(placement: .principal) {
                        Text("Navigation Test")
                            .foregroundColor(.yellow)
                    }
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Text("Settings")
                        .foregroundColor(.yellow)
                }
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Text("Discovery")
                        .foregroundColor(.yellow)
                }
            }
            .navigationBarTitleDisplayMode(.inline)
            .toolbarBackground(Color.red, for: .navigationBar)
            .toolbarBackground(.visible, for: .navigationBar)
            .navigationDestination(for: Company.self) { company in
                DetailView(company: company)
            }
        }
        .accentColor(.yellow)
        .tint(.green)
    }
}

DetailView.swift

      
import SwiftUI

struct DetailView: View {
    var company: Company
    
    var body: some View {
        Text(company.name)
            .toolbarBackground(Color.red, for: .navigationBar)
            .toolbarBackground(.visible, for: .navigationBar)
            .toolbar {
                ToolbarItem(placement: .principal) {
                    Text("Detail View")
                        .foregroundColor(.yellow)
                }
            }
    }
}

Я столкнулся с этим ограничением в своем независимом приложении Apple Watch. Хотя это исправление не строго в SwiftUI, я перешел к файлу Interface.storyboard, выбрал хостинг-контроллер, выбрал инспектор файлов справа, а затем установил цвет рядом с Global Tint в разделе Interface Builder Document.

Это решение основано на принятом ответе, который не использует какую-либо библиотеку и не применяется. глобально.

Это решение устраняет проблемы, которые есть в принятом ответе (например, не работает для начального просмотра или не работает в режиме большого экрана), добавляя хак.

Примечание . Лично я бы не стал использовать этот хак в рабочем коде, тем не менее интересно видеть, что проблемы можно обойти. Используйте на свой страх и риск.

      struct NavigationHackView: View {

    @State private var isUsingHack = false

    var body: some View {
        NavigationView {
            List {
                NavigationLink {
                    Text("Detail view")
                        .navigationTitle("Detail view")
                        .navigationBarTitleDisplayMode(.inline)
                } label: {
                    Text("Show details view")
                }
            }
            .navigationTitle("Hack!")
            .background(
                NavigationConfigurator { navigationController in
                    // required for hack to work
                    _ = isUsingHack
                    navigationController.navigationBar.navigationBarColor(.red, titleColor: .white)
                }
            )
            .onAppear {
                // required for hack to work
                DispatchQueue.main.async {
                    isUsingHack.toggle()
                }
            }
            // required for hack to work, even though nothing is done
            .onChange(of: isUsingHack) { _ in }
        }
    }
}

struct NavigationConfigurator: UIViewControllerRepresentable {

    var configure: (UINavigationController) -> Void = { _ in }

    func makeUIViewController(
        context: UIViewControllerRepresentableContext<NavigationConfigurator>
    ) -> UIViewController {
        UIViewController()
    }

    func updateUIViewController(
        _ uiViewController: UIViewController,
        context: UIViewControllerRepresentableContext<NavigationConfigurator>
    ) {
        guard let navigationController = uiViewController.navigationController else {
            return
        }
        configure(navigationController)
    }
}

extension UINavigationBar {

    func navigationBarColor(
        _ backgroundColor: UIColor, 
        titleColor: UIColor? = nil
    ) {
        let appearance = UINavigationBarAppearance()
        appearance.configureWithOpaqueBackground()
        appearance.backgroundColor = backgroundColor

        if let titleColor = titleColor {
            appearance.titleTextAttributes = [.foregroundColor: titleColor]
            appearance.largeTitleTextAttributes = [.foregroundColor: titleColor]
            // back button appearance
            tintColor = titleColor
        }

        standardAppearance = appearance
        scrollEdgeAppearance = appearance
        compactAppearance = appearance

        if #available(iOS 15.0, *) {
            compactScrollEdgeAppearance = appearance
        }
    }
}

/questions/49907226/swiftui-obnovlyaet-tsvet-zagolovka-paneli-navigatsii/54984249#54984249 этот ответ работает, но если у вас возникли проблемы с нулевым значением navigationController в светлом или темном режиме. Просто добавьте это .. не знаю, почему это работает.

      struct ContentView: View {
   var body: some View {
      NavigationView {
        ScrollView {
            Text("Don't use .appearance()!")
        }
        .navigationBarTitle("Try it!", displayMode: .inline)
        .background(NavigationConfigurator { nc in
            nc.navigationBar.barTintColor = .blue
            nc.navigationBar.background = .blue
            nc.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.white]
        })
    }
   .navigationViewStyle(StackNavigationViewStyle())
   .accentColor(.red)   <------- DOES THE JOB
  }
}
      Post iOS 14 easy way to do:

        protocol CustomNavigationTitle: View {
            associatedtype SomeView: View
            func customNavigationTitle(_ string: String) -> Self.SomeView
        }
        
        extension CustomNavigationTitle {
            func customNavigationTitle(_ string: String) -> some View {
                toolbar {
                    ToolbarItem(placement: .principal) {
                        Text(string).foregroundColor(.red).font(.system(size: 18))
                    }
                }
            }
        }
        
        extension ZStack: CustomNavigationTitle {}
    
    Suppose your root view of view is made with ZStack
    it can be utilised below way
    
    ZStack {
    }. customNavigationTitle("Some title")
       .toolbar {
            ToolbarItem(placement: .principal) {
                Text("Your Score \(count)")
                .foregroundColor(.white)
                .font(.largeTitle)
                .bold()
                .shadow(radius: 5, x: 0, y: -10)
            }
            
        }

Если вы не возражаете изменить его глобально, я обнаружил, что вход в каталог ресурсов и настройка AccentColor работает.

Решение, которое сработало для меня, состояло в том, чтобы использовать метод UINavigationBarAppearance(), а затем добавить .id() в NavigationView. Это автоматически перерисовывает компонент при изменении цвета.

Теперь вы можете иметь реактивные изменения цвета на основе механизма состояний.

      var body: some Scene {
  let color = someValue ? UIColor.systemBlue : UIColor.systemGray3

  let custom = UINavigationBarAppearance()
  custom.configureWithOpaqueBackground()
  custom.backgroundColor = color
  UINavigationBar.appearance().standardAppearance = custom
  UINavigationBar.appearance().scrollEdgeAppearance = custom
  UINavigationBar.appearance().compactAppearance = custom
  UINavigationBar.appearance().compactScrollEdgeAppearance = custom

  return WindowGroup {
    NavigationView {
      content
    }
      .id(color.description)
  }
}

Самый простой способ, который я нашел, был:

      init() {
    UINavigationBar.appearance().tintColor = UIColor.systemBlue
    }

вместо systemBlue вы можете использовать любые другие цвета по вашему желанию. Вы должны реализовать это вне "var body: some View {}". вы также можете добавить:

      @Environment(/.colorScheme) var colorScheme

на вершине init()а затем вы можете использовать .dark или .light, чтобы изменить цвет так, как вы хотите, в темном и светлом режиме. пример:

      init() {
    UINavigationBar.appearance().tintColor = UIColor(colorScheme == .dark ? .white : Color(#colorLiteral(red: 0.2196078449, green: 0.007843137719, blue: 0.8549019694, alpha: 1)))
    }

Я использовал ViewModifier, чтобы применить собственный цвет для панели навигации. Я не могу сказать, что приведенный ниже код изменил фактическую панель навигации, но я считаю, что это работает лучше, чем другие.

В отличие от UINavigationBar.appearance(), он не применяется ко всем представлениям.

  • Создайте ViewModifer — я использую ShapeStyle , поэтому вы можете применить любой стиль к панели навигации. (вроде - градиент, цвет)
      struct NavigationBarStyle<S: ShapeStyle>: ViewModifier {
    private var bgStyle: S
    private var viewBackgroundColor: Color
    
    init(_ bgStyle: S, viewBackgroundColor: Color) {
        self. bgStyle = bgStyle
        self.viewBackgroundColor = viewBackgroundColor
    }
    
    func body(content: Content) -> some View {
        ZStack {
            Color(UIColor.systemBackground)
                .ignoresSafeArea(.all, edges: .bottom)
            
            content
        }
        .background(bgStyle)
    }
}

extension View {
    func navigationBarStyle<S: ShapeStyle>(_ bgStyle: S, viewBackgroundColor: Color = Color(UIColor.systemBackground)) -> some View {
        modifier(NavigationBarStyle(bgStyle, viewBackgroundColor: viewBackgroundColor))
    }
}

Примечание. Вы должны применить этот модификатор к самому верхнему виду, чтобы он работал. например -

      struct NewView: View {
    var body: some View {
        NavigationView {
            VStack {
                HStack {
                    Text("H Stack")
                }
                // .navigationBarStyle(Color.orange) not the right place
                Text("Hello World")
            }
            .navigationBarStyle(Color.orange) // right place to apply
        }
    }
}

Другие вопросы по тегам