更新导航栏标题颜色

如何在 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))

有人帮忙吗?

133316 次浏览

如果您的内容是

struct MyContent : View {
...
}

then you can put it like this inside a navigation view with a red background:

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

我会更新我的答案,只要我知道如何更新标题文本本身。

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

我已经开发了一个自定义 SwiftUI 导航的小例子,它可以提供完整的视觉定制和程序导航。它可以用来替代 NavigationView。

Here is the NavigationStack class that deals with currentView and navigation stack:

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


你可以看看 这里:的完整示例并解释一下:

附注: 我不知道为什么这个被删除了。我认为它回答了这个问题,因为它是 NavigationView 的一个完美的功能替代品。

在 SwiftUI 中,不能直接更改导航 TitleColor,

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

我希望它能起作用。谢谢! !

没有需要使用 .appearance()在全局执行此操作。

Although SwiftUI does not expose navigation styling directly, you can work around that by using UIViewControllerRepresentable. Since SwiftUI is using a regular UINavigationController behind the scenes, the view controller will still have a valid .navigationController property.

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


Modified navigation bar

I still haven't figured out how to do the foreground color on a per-view basis, but I did figure out a simple workaround for the background color.

如果使用 .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)的帧高。

在 SwiftUI 中使用以下代码进行颜色自定义

这是为主体背景颜色:-

struct ContentView: View {


var body: some View {


Color.red
.edgesIgnoringSafeArea(.all)


}


}

enter image description here

对于导航栏:-

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


}


}


}

enter image description here

For Other UI Elements Color Customization

struct ContentView: View {


@State var msg = "Hello SwiftUI😊"


var body: some View {


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


}
}

enter image description here

13.4级更新

注意: 第二天再来看这个,我的一些问题可能是由于我的非标准设置造成的: 我仍然在运行 mojave,但已经手动添加了13.4支持文件(通常只能通过 xcode 11.4获得,这需要 catalina)。我提到这一点是因为我也有一些标签栏自定义颜色的问题,但我只是注意到,这些只有当我有手机实际上插入和运行的应用程序从 xcode。如果我拔掉插头,只是正常运行应用程序,我没有看到标签栏问题,所以有可能导航栏问题有一些相似之处..。

(我想加上这一点作为对上述 Arsenius 的回答(目前已被接受的回答)的评论,但我没有代表,所以...)

我一直在用那个方法,直到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() }
}

(in my app, i have a Prefs object which keeps track of colors, etc.)

然后,在实例化网站上,做这样的事情:

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 ()。你可能想用不同的方式,但我已经有了这个变量,因为其他原因... 还有一些其他的东西,特定于我的应用程序,例如,颜色相关的对象,但你得到的想法。

下面是对我有效的解决方案,您需要从一个 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
}

and then in your content view:

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

and if you want to change the color at some point, such as in a modal view, use the answer given 给你

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

Main View Modal View

我已经搜索了这个问题,并找到了一个伟大的文章关于这一点,你可以包装设置的导航栏样式作为一个视图修饰符。

看看这个 林克

注意: 我认为您需要在这个例子中更新一些代码,添加 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)

我希望能成功。

在 Arsenius 的答案的基础上,我发现让它始终如一地工作的一个优雅的方法是子类 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)
}
}
}

在 iOS14中,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)
}
}
}
}

Definitely there are already a few good answers, but all of them will cover only part of the job:

  1. @ Arsenius伟大的解决方案-给好点开始

  2. @ EngageTheWarpDrive的优雅方式-这肯定提高可用性

  3. 对于最新版本的 iOS 和 SwiftUI,@Thahir建议使用工具栏

几乎没有更多的建议建议为 UINavigationBar使用 UIAppearence全局配置-对我来说,全局更改不是一个好主意,可能并不总是合适的。

我最终将所有的建议合并到下一个代码中:

  1. navigationBar配置创建 NavigationControllerRepresentablemodifier:

     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. 正如你所看到的,这里我们确实需要一些桥梁之间的 ColorUIColor。从 iOS 14开始-u 可以只用 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)
    }
    

希望这能对某人有所帮助;)

Https://stackoverflow.com/a/58427754/4709057 这个答案是有效的,但是如果你遇到导航/控制器在亮或暗模式下为零的问题。加上这个。.不知道为什么会有用。

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

我采取了一种稍微不同的方法; 我想改变 only的标题文本颜色,而不是关于 NavigationBar的其他内容。利用上面的内容和 this作为灵感,我得出了以下结论:

import SwiftUI


extension View {
/// 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
}
}

This requires iOS 14 because UIColor.init(_ color: Color) requires iOS 14.

Which can be leveraged as such:

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

Which in turn yields:

Red navigation title

导航视图。

但是要更改导航视图本身,需要在 init()中使用 UINavigationBar Appearance()

我正在寻找这个问题,并发现了一个关于 的伟大的文章。我通过这篇文章修改了您的代码,并取得了成功。这里,我如何解决这个问题:

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

你也可以举一些 here的例子

与设置影响 所有导航条的 appearance()不同,您可以使用 SwiftUI-内省单独设置它们。

例如:

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

Result:

Result

使用 SwiftUI 的 WatchOS 导航标题颜色
Side note for watchOS is that you don't need to fiddle with the navigation color. It's the Watch Accent color you need to change. In your project go into WatchProjectName->Asset->Accent and change this enter image description here

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

对我有效的解决方案是使用 UINavigationBar卖相()方法,然后添加。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
}

而不是系统蓝色,你可以使用任何其他颜色,你希望。 You have to implement this outside the "var body: some View {}". 你也可以加上:

@Environment(/.colorScheme) var colorScheme

init()的顶部,然后您可以使用。黑暗或者。光改变颜色的方式,你想在黑暗模式和光模式。例如:

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

这个解决方案建立在不使用任何库也不在全局应用 UINavigationBarAppearance的公认答案的基础上。

这个解决方案通过添加一个 hack 来修复已接受的答案所存在的问题(比如不适用于初始视图或不适用于大型显示模式)。

注意 我个人不会在生产代码中使用这种黑客技术,不过看到这些问题能够得到解决还是很有趣的。使用风险自负。

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

基于这个 https://stackoverflow.com/a/66050825/6808357我创建了一个扩展,在这里你可以同时设置背景颜色和标题颜色。

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

Happy coding!

Demo

IOS14,你可以有任何自定义视图你想(包括自定义文本与自定义颜色和字体)

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

你也可以从 iOS 16设置导航条颜色,比如:

.toolbarBackground(.red, in: .navigationBar)

I have used ViewModifier to apply custom colour for navigation bar. I can't say below code modified actual navigation bar, but I find this work around better than above others.

与 UINavigationBar.face ()不同,它不会应用于所有视图。

  • Create a ViewModifer - I have use ShapeStyle, so you can apply any style to navigation bar. (like - gradient, colour)
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))
}
}


Note - you have to apply this modifier on the top most view to work. e.g -

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