如何在SwiftUI中的NavigationView中设置ScrollView的背景颜色

22
我在SwiftUI中无法为ScrollView设置背景颜色。当我使用.background(Color.red)时,背景被裁剪,因此它不会出现在导航栏下方,滚动似乎也出了问题。 我尝试了几种解决方案,但每一种都没有起作用。 我有一个简单的视图层次结构。
NavigationView {
    ScrollView([.vertical], showsIndicators: true) {
        VStack {
            ForEach(0...50, id: \.self) { _ in
                Text("Text text")
            }
        }
    }
    .navigationBarTitle("Title", displayMode: .large)
}
.navigationViewStyle(StackNavigationViewStyle())

它按预期工作

enter image description here

现在,我想添加一个背景颜色,我尝试了以下解决方案

1

NavigationView {
    ScrollView([.vertical], showsIndicators: true) {
        VStack {
            ForEach(0...50, id: \.self) { _ in
                Text("Text text")
            }
        }
    }
    .background(Color.red)
    .navigationBarTitle("Title", displayMode: .large)
}
.navigationViewStyle(StackNavigationViewStyle())

结果

enter image description here

2

NavigationView {
    ZStack {
        Color.red
        ScrollView([.vertical], showsIndicators: true) {
            VStack {
                ForEach(0...50, id: \.self) { _ in
                    Text("Text text")
                }
            }
        }
        .navigationBarTitle("Title", displayMode: .large)
    }
}
.navigationViewStyle(StackNavigationViewStyle())

结果

enter image description here

3

NavigationView {
    ZStack {
        Color.red.edgesIgnoringSafeArea([.all])
        ScrollView([.vertical], showsIndicators: true) {
            VStack {
                ForEach(0...50, id: \.self) { _ in
                    Text("Text text")
                }
            }
        }
        .navigationBarTitle("Title", displayMode: .large)
    }
}
.navigationViewStyle(StackNavigationViewStyle())

结果

enter image description here

如何在NavigationView中包装的ScrollView下设置背景颜色?
// 编辑:
以下动画展示了一个理想的效果(使用UIKit制作)。

enter image description here


2
我也有同样的问题。看起来是另一个SwiftUI的Bug。 - Apostolos
1
即使我将scrollView放入ZStack { Color.red,ScrollView }中,我仍然遇到同样的问题。 - Apostolos
你找到解决方案了吗? - arata
很遗憾,我已经放弃了SwiftUI并转向UIKit。SwiftUI还不完整,不能用于生产环境... - kampro
仍然无法工作。 - mawus
6个回答

7

在尝试了所有可能的方案后,我找到了以下解决方案,它完美地实现了你想要达到的目标。

struct DemoView: View {
    
    init(){
        let navigationBarAppearance = UINavigationBarAppearance()
        navigationBarAppearance.backgroundColor = UIColor.red
        UIScrollView.appearance().backgroundColor = UIColor.red
    }
    
    var body: some View {

        NavigationView{
                ScrollView{
                    VStack{   
                        ForEach(0..<30, id: \.self){ _ in
                                Text("Text Text").foregroundColor(Color.black)
                        }
                    }.frame(maxWidth: .infinity)
                     .background(Color(UIColor.red))
            
            }.navigationBarTitle("Title")
        }  
    }
}


希望这有所帮助;)

但是如果我也想实现一个暗色主题呢? - leonboe1
如果您为视图添加背景颜色,则您的深色主题将使用您设置的相同颜色作为背景颜色(而不是深色)。如果您设置了深色主题,则仅默认颜色会使用深色。@leonboe - user2580
如果检测到从暗模式切换到亮模式或从亮模式切换到暗模式,那么更改背景颜色就不可能了吗? - leonboe1
一旦设置了背景颜色,无论是浅色模式还是深色模式都不会有任何影响。它将始终保持您所设置的相同颜色。 - user2580
警告:对于使用Xcode 12 / SwiftUI 2的任何人来说,将.padding()添加到ScrollView之外的任何内容都会破坏我项目中上述修复的功能。必须在ScrollView内的元素中添加Padding,然后才能正常工作。这显然是一个经过充分考虑的框架的便利特性。 - Beginner
这不是一个好的答案,因为这个改变是全局性的。 - user2641891

4

您可以使用下面使用 List View 的代码来实现几乎相同的行为。

struct DemoView: View {
    init(){
        let navigationBarAppearance = UINavigationBarAppearance()
        navigationBarAppearance.backgroundColor = UIColor.red
        UITableView.appearance().separatorStyle = .none
        UITableView.appearance().backgroundColor = UIColor.red
    }
    
    var body: some View {

        NavigationView{
 
                List{

                    ForEach(0..<30, id: \.self){ _ in
                        
                        Text("Text Text")
                        
                    }.listRowBackground(Color(UIColor.red))
            }
            }.navigationBarTitle("Title")
        }
        
    }
}

该代码生成了以下视图:12

2
这是一个不太正规的 SwiftUI 解决方案:
iOS 13 和 iOS 14 适用。
NavigationView {
    ScrollView {
        VStack {
            // ...
        }
        .background(Color.red.frame(height: 99999999))
    }
}

似乎对我不起作用。红色背景正确地延伸到顶部和底部,但宽度不足以填满整个屏幕。 - Daniel Lyons
3
被踩了:你永远不应该硬编码使用数字的高度或其他测量单位。请不要使用这段代码。 - dbDev
如果你要在这里使用一个固定的框架,至少要使用GeometryReader来确定框架的高度。 - TimD

1

我遇到了同样的问题。在 .background() 修饰符之后,我添加了 .padding(.top),然后它就按照预期工作了。


0
你可以像这样做:
struct ContentView: View {
    init() {
        //Use this if NavigationBarTitle is with Large Font
        UINavigationBar.appearance().backgroundColor = .red
    }
    var body: some View {
        NavigationView {
            ScrollView([.vertical], showsIndicators: true) {
                VStack {
                    ForEach(0...70, id: \.self) { _ in
                        Text("Text text")
                    }
                }.frame(minWidth: 0, maxWidth: .infinity)
                    .background(Color(UIColor.red))
            }
            .navigationBarTitle("Title", displayMode: .large)
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

它将会生成一个类似这样的视图: 输入图像描述

enter image description here

我知道这不是完整的解决方案,因为顶部安全边缘的原因,但希望它能帮助你更接近目标。

另外,我尝试忽略顶部安全边缘,但会导致导航栏间距出现问题。


这是一种hack方法,不以应有的方式工作。我不想改变导航栏的颜色,如果我的背景是图片或渐变呢?我觉得SwiftUI很糟糕。 - kampro
2
哈哈,SwiftUI 还没有完全开发完成。 - 39fredy

0
这个有效(请参见详情):
ScrollView(showsIndicators: false) {
    VStack {
        ForEach(0...70, id: \.self) { _ in
            Text("Text text")
        }
    }
    .frame(width: UIScreen.main.bounds.width)
}
.background(.pink)
.scrollContentBackground(.hidden)

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