如何在SwiftUI中更改表单的背景颜色?

46

我想为一个表单更改“浅灰色”背景颜色,但.foregroundColor(Color.blue).background(Color.blue)似乎不起作用。

struct ContentView : View {

 @State var value = ""

    var body: some View {
        Form {
            Section(header: Text("First Name")) {
                TextField($value)
            }
            Section(header: Text("Last Name")) {
                TextField($value)
            }
        }.foregroundColor(Color.blue)

    }
}

enter image description here


1
你可能需要发布更多的代码,因为像 background 修饰符这样基本的东西似乎不是你的问题。这是一个模态弹出窗口吗?你正在使用 ZStack 吗?请给我们更多的细节,或者接受 @Quinn 给出的答案。让我们复制这个问题。 - user7014451
@dfd 这是我唯一的视图,一个带有两个字段的表单(旨在成为注册表单),可能会添加一个按钮,但没有任何弹出窗口或 ZStack。 我已经尝试在Form上使用.background(Color.blue),但它不起作用。 我猜Form是一个特殊的视图,或者可能只是一个错误,有人找到了解决方法。 - Sorin Lica
找到了。我会发布一个答案,如果你需要一些调整,请告诉我。 - user7014451
10个回答

88

iOS 16

您可以通过向Form应用以下修饰符来隐藏默认背景以显示底层视图:

.scrollContentBackground(.hidden)

iOS 13和15

在iOS中,所有SwiftUI的List都由一个UITableView支持。因此,您需要更改tableView的背景颜色。但由于ColorUIColor值有些不同,所以可以摆脱UIColor

struct ContentView: View {
    
    init(){
        UITableView.appearance().backgroundColor = .clear
    }
    
    @State var value = ""
    
    var body: some View {
        Form {
            Section(header: Text("First Name")) {
                TextField("First Name", text: $value)
            }
            Section(header: Text("Last Name")) {
                TextField("Last Name", text: $value)
            }
        }
      /*.scrollContentBackground(.hidden)*/ //  this line will work only on iOS 16 and above 
        .foregroundColor(Color.blue)
        .background(Color.yellow)
    }
}

现在您可以使用任何背景(包括所有Color

预览

请注意,上部和下部的白色区域是安全区域,您可以使用.edgesIgnoringSafeArea()修饰符去掉它们。


还原

由于UITableView.appearance().backgroundColor全局应用,您可以使用.onAppear修饰符在不同的视图中更改它(因为它是全局更改)。因此,您可以使用另一个onAppearonDisappear将其重置回您想要的状态。

默认颜色为:

UIColor.systemGroupedBackground适用于分组样式。和

UIColor.systemBackground适用于普通样式

它们都具有在暗模式和亮模式下的自动支持。


UITableView.appearance().backgroundColor = .clear 这样修改风格是全局性的,这不是一个理想的解决方案。但是,我找不到其他的替代方案。 - William Grand
你可以使用.onAppear()修饰符使其仅在该页面上起作用。 ;) @WilliamGrand - Mojtaba Hosseini
当然,你应该使用另一个onAppearonDisappear来将其重置回你想要的状态;) @WilliamGrand - Mojtaba Hosseini
我知道,但我想更改它的默认值。我怎么知道默认表单背景RGB代码? - Kenan Nur
4
对于 iOS 14,这个说法已经不正确了。UITableView 不再支持后端列表。 - Ben Patch
显示剩余5条评论

15

适用于所有版本

看到这些解决方案后,我为您创建了一个修饰符,供iOS 16及以下版本使用。

struct FormHiddenBackground: ViewModifier {
    func body(content: Content) -> some View {
        if #available(iOS 16.0, *) {
            content.scrollContentBackground(.hidden)
        } else {
            content.onAppear {
                UITableView.appearance().backgroundColor = .clear
            }
            .onDisappear {
                UITableView.appearance().backgroundColor = .systemGroupedBackground
            }
        }
    }
}

要使用它,您只需要在表单提交后进行更新。

 Form {
     Text("Test text")
 }
 .frame(height: 400)
 .modifier(FormHiddenBackground())

2
谢谢。这是唯一在iOS16上能够使用Xcode 14.2的解决方案。 - Lawrence Edmondson

9

试一下这个

.onAppear {
   UITableView.appearance().backgroundColor = .blue
}

2
UITableView.appearance().backgroundColor = .blue 这种方式会全局改变样式,这并不是一个理想的解决方案。但是,我没有找到其他替代方案。 - William Grand
对于不想普遍更改它的任何人,请参考此答案。 - Okhan Okbay

8
上面 Mojtaba Hosseini 的回答是有效的,但是在 init() 语句中添加 UITableView 语句不是一个好的做法。这是因为它 "硬编码" ContentView 的 init 参数。在本例中,它没有参数,所以一切正常,但是如果将 @ObservedObject 添加到视图中,则会破坏 init 函数。
更简单的方法是将 UITable 语句添加到 body 中,显式返回 Form 并删除 init()。
var body: some View {
    UITableView.appearance().backgroundColor = .clear
    return Form {...}
 }

然而,在 Form 上设置背景颜色通常会如预期地工作。在 ContentView 屏幕上无法工作可能是一个 bug。


错误:类型“()”无法符合“View”;只有结构体/枚举/类类型可以符合协议。 - FontFamily

7

不要更改全局的appearance()

例如,您可以使用 UITableView.appearance().backgroundColor = .redForm 的背景颜色设置为红色。这可以放在视图的 init 中,但是这会影响每个 ListForm

或者,您可以使用 SwiftUI-Introspect 来自定义单个元素,例如:

struct ContentView: View {
    @State private var value = ""

    var body: some View {
        Form {
            Section(header: Text("First Name")) {
                TextField("First", text: $value)
            }

            Section(header: Text("Last Name")) {
                TextField("Last", text: $value)
            }
        }
        .introspectTableView { $0.backgroundColor = .systemBlue }
        .foregroundColor(Color.blue)
    }
}

Result

您还可以添加以下内容到每个部分,使部分也变为蓝色:
.listRowBackground(Color.blue)

1
在iOS 16中不再起作用,因为表单视图现在由集合视图支持,而不是表视图。这说明了假设底层实现始终相同的危险性。 - Michael Long

1

将以下代码复制到每个表单视图中:

Form {
    // Your form view 
} 
.onAppear { // ADD THESE AFTER YOUR FORM VIEW
    UITableView.appearance().backgroundColor = .clear 
}
.onDisappear { // CHANGE BACK TO SYSTEM's DEFAULT
    UITableView.appearance().backgroundColor = .systemGroupedBackground 
} 
.background(.yellow) // Add your background color

1
如果您不想修改Form的安全区域,也可以使用ZStack
struct ContentView: View {
    
    init(){
        
        UITableView.appearance().backgroundColor = .clear
    }
    
    @State var value = ""
    
    var body: some View {
        ZStack {
            Color(UIColor.systemYellow)
                .edgesIgnoringSafeArea(.all)
            Form {
                Section(header: Text("First Name")) {
                    TextField("First Name", text: $value)
                }
                Section(header: Text("Last Name")) {
                    TextField("Last Name", text: $value)
                }
            }
        }
    }
}

1
在iOS 17中,您可以通过组合来更改Form的背景颜色。
.background(Color.yellow)
.scrollContentBackground(.hidden)

应用它们在表单修饰符上。
Form {
  ...
}
.background(Color.yellow)
.scrollContentBackground(.hidden)

0
以上的解决方案并没有真正解决我想要实现的功能。我想要一个具有清晰背景的初始屏幕,而后续屏幕应该具有默认的iOS systemGroupedBackground颜色。使用appear()和disappear()对我来说行不通,因为在各个选项卡之间切换会导致外观上的错误。
我想出了以下解决方案,它借鉴了以上的解决方案。
对于我的ContentView屏幕,我在Struct内部插入了以下代码。
init(){
    UITableView.appearance().backgroundColor = .clear
}

这是一个全局变更,影响所有表单。

对于所有需要默认颜色的表单,我在 Form {} 外部插入了这段代码。

.background(Color(.systemGroupedBackground))

-2
为了适用于所有的iOS版本,你可以为View创建一个扩展。
extension View {

    @ViewBuilder
    func hideFormBackground() -> some View {
        if #available(iOS 16.0, *) {
            scrollContentBackground(.hidden)
        } else {
            introspectTableView {
                $0.backgroundColor = .clear
            }
        }
    }
}

然后,在声明表单时使用它:

Form {
    SomeContent
}
.hideFormBackground()

这需要深思熟虑,不是一个合适的解决方案。 - Jordi Bruin

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