如果在SwiftUI中使用NavigationView,如何更改背景颜色?

55

我想为全屏更改背景颜色。我正在使用NavigationView,我希望将灰色设为背景颜色(而不是默认的白色)

struct ContentView : View {
    var body: some View {
        NavigationView {
            ScrollView {
                Text("Example")
            }
            .navigationBarTitle("titl")
        }
    }
}

.background(Color.red) 在任何地方均不起作用。

预览

13个回答

46

如果你只是将你的内容嵌入到 NavigationView 中的一个 ZStack 中,那么你应该能够在主要内容下面加上颜色。

struct ContentView : View {
    var body: some View {
        NavigationView {
            ZStack {
                Color.red.edgesIgnoringSafeArea(.all)
                ScrollView {
                    Text("Example")
                }
                .navigationBarTitle("title")
            }
        }
    }
}

8
在我的情况下,一开始似乎工作正常,但后来发现它会导致我的应用程序崩溃。我的 "ContentView" 已经在一个 ZStack 中了,当这个 "ContentView" 从树中移除时就会发生崩溃。更准确地说,是使用 "edgesIgnoringSafeArea" 在颜色上造成了应用程序崩溃。所以目前,我还没有找到有效的方法来改变导航栏颜色。恐怕现在没有解决方案... - neywen
顺便提一下,它也适用于LinearGradient! - Santiago

20

补充Mattis Schulte的回答,我遇到的一个副作用是状态栏不会继承背景颜色。

然而,当您将列表(例如)向上滚动到视图顶部时,iOS会切换到内联标题视图(带有居中的NavigationBarTitle),并在状态栏区域着色,留下相当不理想的用户体验。

我能够使用的解决方法是:

import SwiftUI

let coloredNavAppearance = UINavigationBarAppearance()
   
struct ListView: View {

    init() {
        coloredNavAppearance.configureWithOpaqueBackground()
        coloredNavAppearance.backgroundColor = .systemBlue
        coloredNavAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        coloredNavAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
               
        UINavigationBar.appearance().standardAppearance = coloredNavAppearance
        UINavigationBar.appearance().scrollEdgeAppearance = coloredNavAppearance

    }

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("General")) {
                    HStack {
                        Text("ListView #1")
                        Spacer()
                        Text("data")
                            .multilineTextAlignment(.trailing)
                    }
                    HStack {
                        Text("ListView #2")
                        Spacer()
                        Text("data")
                            .multilineTextAlignment(.trailing)
                    }
                }

            }
            .navigationBarTitle("NavBar Title")
        }
    }
}


struct ListView_Previews: PreviewProvider {
    static var previews: some View {
        ListView()
    }
}


希望这能帮助其他人。感谢https://sarunw.com/posts/uinavigationbar-changes-in-ios13/提供的支持。

谢谢。我甚至不知道应该搜索哪个关键字来解决这个问题。 - William Tong

15

最新的解决方案是为UINavigationController编写一个扩展,如下所示:

extension UINavigationController {
    override open func viewDidLoad() {
        super.viewDidLoad()

    let standard = UINavigationBarAppearance()
    standard.backgroundColor = .red //When you scroll or you have title (small one)

    let compact = UINavigationBarAppearance()
    compact.backgroundColor = .green //compact-height

    let scrollEdge = UINavigationBarAppearance()
    scrollEdge.backgroundColor = .blue //When you have large title

    navigationBar.standardAppearance = standard
    navigationBar.compactAppearance = compact
    navigationBar.scrollEdgeAppearance = scrollEdge
 }
}

或者,旧的方法:

在你的结构初始化程序中更改UITableView的颜色,如下所示:

struct ContentView : View {
init() {
    UITableView.appearance().backgroundColor = .red
    }
var body: some View {
    NavigationView {
        ScrollView {
            Text("Example")
        }
        .navigationBarTitle("title")
    }
  }
}

这会为整个应用程序配置导航栏吗? - aheze
@aheze,是的,在 appdelegate 中添加它。 - FRIDDAY
您是否可以在UITableView上使用扩展解决方案? - Nick

6
iOS 16及以上版本的导航栏:
使用以下代码设置背景颜色为红色: .toolbarBackground(.red, for: .navigationBar)

不错!然而,这似乎只在工具栏不透明时生效。因此,要么当用户滚动时,要么使用 toolbar(visible: for:) 手动设置导航栏始终可见。 - codingFriend1

5

只需将以下代码添加到您的代码初始化器中 UIScrollView.appearance().backgroundColor = UIColor.red。但不幸的是,这种解决方案有很多副作用。


3

以下是我的解决方案,因为在我的情况下其他的解决方案都不起作用,所以我想分享一下...

对于导航栏颜色,可以添加一个类似这样的初始化器:

struct ContentView: View {
    init() {
        UINavigationBar.appearance().backgroundColor = .red
    }
    var body: some View {
        NavigationView {
            ScrollView {
                ...
            }
        }
    }
}

如果您想编辑ScrollView的背景颜色,可以像这样操作: 我已经为ListView完成了此操作,但您也可以为ScrollView进行操作。

struct ListBackgroundColor: ViewModifier {

    let color: UIColor

    func body(content: Content) -> some View {
        content
            .onAppear() {
                UITableView.appearance().backgroundColor = self.color
                //(Optional) Edit colour of cell background
                UITableViewCell.appearance().backgroundColor = self.color
            }
    }
}   

extension View {
    func listBackgroundColor(color: UIColor) -> some View {
        ModifiedContent(content: self, modifier: ListBackgroundColor(color: color))
    }

}

界面示例 https://imgur.com/a/TQ9c5Sc


2

好的,我刚试了Omar的解决方案,但如果在堆栈中有其他视图,则不起作用。

因此,到目前为止我看到的最好的答案实际上是更改NavigationView的底层背景颜色(在OP的原始问题中),只需设置UIView外观的背景颜色,正如这个答案所提示的:

Original Answer翻译成"最初的回答"

UIView.appearance().backgroundColor = UIColor.red

3
我尝试了您的解决方案,我得到了期望的背景颜色,但其他所有内容都消失了。 - Mattis Schulte
我也遇到了和@MattisSchulte一样的问题。 - Sona

1

对于iOS 16,以下代码可以使整个屏幕变成黑色背景:

 var body: some View {
    GeometryReader { geometry in
        NavigationView {
            List {
                ForEach(solutions) { solution in
                }
                .listRowBackground(Color.black)
            }
            .listStyle(.plain)
            .searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always))
            .navigationBarTitleDisplayMode(.inline)
            .navigationTitle("My Solutions")
            .toolbar {
                Button("Add") {
                    addSolution()
                }
                .foregroundColor(.white)
            }
            .background(.black)
        }
    }
 }

1

你可以使用一个小技巧,添加一个没有文本的文本视图,并将背景颜色设置为所需的颜色,就像以下示例:

Text(" ")
    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
    .background(Color.red)
    .edgesIgnoringSafeArea(.all)

代码添加颜色 NavigationView { ZStack { Text(" ") .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity) .background(Color.red) .edgesIgnoringSafeArea(.all) ScrollView { ChooseView() ChooseView() } } .navigationBarTitle("标题") } 但是滚动不正确(导航未翻译) - Ivan Vorobei
视图无法滚动?您确定scrollview在textview的上方吗?您能上传一张您要滚动的数据图片吗?此外,如果您移除textview,您能否滚动? - omar
2
不滚动导航栏从大状态到基本状态。 - Ivan Vorobei
天啊,我无法相信这个hack竟然是必需的,只是为了一个应该有backgroundColor属性的东西。 - PostCodeism
2
这只是一个hack..所以当你使用它时,你应该预料到会有bug。如果你不想在未来遇到问题,比如无法滚动屏幕,我建议你远离这个解决方案。 - alexisSchreier

0

适用于iOS 14及以下版本

UINavigationBar.appearance().barTintColor = UIColor.red

适用于iOS 15

NavigationView {
            ZStack(alignment: .top) {
                GeometryReader { reader in
                    Color.red
                        .frame(height: reader.safeAreaInsets.top, alignment: .top)
                        .ignoresSafeArea()
                }

                // your content view
            }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接