如何在 SwiftUI 中修改 List 的背景色?

我试图在 SwiftUI 中重新创建一个用 UIKit 构建的 UI,但是遇到了一些小问题。

I want the change the color of the List here, but no property seems to work as I expects. Sample code below:

struct ListView: View {
@EnvironmentObject var listData: ListData


var body: some View {
NavigationView {
List(listData.items) { item in
ListItemCell(item: item)
}
.content.background(Color.yellow) // not sure what content is defined as here
.background(Image("paper-3")) // this is the entire screen
}
}
}


struct ListItemCell: View {
let item: ListItem


var body: some View {


NavigationButton(destination: Text(item.name)) {
Text("\(item.name) ........................................................................................................................................................................................................")
.background(Color.red) // not the area I'm looking for
}.background(Color.blue) // also not the area I'm looking for
}
}

I want to change the WHITE area

99949 次浏览

我能够得到整个列表,以改变颜色使用彩色倍增(颜色:)。只需将这个修饰符添加到列表视图的末尾,然后填充就会将表推到设备边缘。例如:

List {...}.colorMultiply(Color.green).padding(.top)

Https://www.hackingwithswift.com/quick-start/swiftui/how-to-adjust-views-by-tinting-and-desaturating-and-more

好的,我找到了给列表行着色的解决方案:

struct TestRow: View {


var body: some View {
Text("This is a row!")
.listRowBackground(Color.green)
}
}

然后是身体:

List {
TestRow()
TestRow()
TestRow()
}

这和我预期的一样,但是我还没有找到如何消除行之间的分界线..。

如果尝试使用 .listRowBackground和应用 .padding使用 SwiftUI 创建浮动类型单元格,那么有人可能会发现这很有用

var body: some View {
NavigationView {
List {
ForEach (site) { item in
HStack {
Text(String(item.id))


VStack(alignment: .leading) {
Text(item.name)
Text(item.crop[0])
}


}.listRowBackground(Color.yellow)
.padding(.trailing, 5)
.padding(.leading, 5)
.padding(.top, 2)
.padding(.bottom, 2))
}
}
.navigationBarTitle(Text("Locations"))
}
}

我假设 listRowPlatterColor修饰符应该这样做,但不是 Xcode 11 Beta 11M336w

var body: some View {
List(pokemon) { pokemon in
PokemonCell(pokemon: pokemon)
.listRowPlatterColor(.green)
}
}

我不知道什么是连接,但如果你包装的名单与 Form它是工作。

Form {
List(viewModel.currencyList, id: \.self) { currency in
ItemView(item: currency)
}
.listRowBackground(Color("Primary"))
.background(Color("Primary"))
}

可以通过改变 UITableView的外观来实现。

UITableView.appearance().backgroundColor = UIColor.clear

只要把这一行放在 AppdelegatedidFinishLaunchingWithOptions方法中。 取代 UIColor.clear设置任何颜色,你想添加在背景颜色的 list

enter image description here

struct ContentView: View {


var strings = ["a", "b"]


var body: some View {


List {
ForEach(strings, id: \.self) { string in
Text(string)
}.listRowBackground(Color.green)
}
}
}

我已经启发了一些配置器,用于配置每页 NavigationView 导航栏样式和编写一些简单的 UITableView 每页配置器不使用 UITableView.look ()全局方法

   import SwiftUI


struct TableViewConfigurator: UIViewControllerRepresentable {


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


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


UIViewController()
}


func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<TableViewConfigurator>) {


let tableViews = uiViewController.navigationController?.topViewController?.view.subviews(ofType: UITableView.self) ?? [UITableView]()


for tableView in tableViews {
self.configure(tableView)
}
}
}

然后需要 UIView 扩展来查找所有的 UITableView

extension UIView {
func subviews<T:UIView>(ofType WhatType:T.Type) -> [T] {
var result = self.subviews.compactMap {$0 as? T}
for sub in self.subviews {
result.append(contentsOf: sub.subviews(ofType:WhatType))
}
return result
}
}

最后的用法是:

List {


}.background(TableViewConfigurator {
$0.backgroundColor = .red
})

也许有一件事情需要改进,那就是导航控制器的使用?.在视图控制器层次结构中,即使没有导航控制器,topViewController 也能使其正常工作

对我来说,在 SwiftUI 中更改 List 背景的一个完美解决方案是:

struct SomeView: View {
init(){
UITableView.appearance().backgroundColor = UIColor(named: "backgroundLight")
}
...


}

这会将整个列表的背景设置为绿色:

init() {
UITableView.appearance().separatorStyle = .none
UITableViewCell.appearance().backgroundColor = .green
UITableView.appearance().backgroundColor = .green
}

名单还不完美。

一个选择是像这样使用它-> List { ForEach(elements) { }}而不是 List($elements)

在我看来,这是目前为止最有效的方法。 就像@FontFamily 说的,它不应该破坏任何 List默认行为,比如滑动。

。彩色倍增(...)

作为一个选项,您可以 .colorMultiply(Color.yourColor)修饰符。

警告 : 这不会改变颜色!这只对当前颜色应用 Multiply修饰符。请在任何操作之前阅读问题,因为您可能正在寻找: “如何在 SwiftUI 中 改变列表的背景颜色”,这将不会为您工作。Something

例如:

List (elements, id:\.self ) { element in


Text(element)


}
.colorMultiply(Color.red) <--------- replace with your color

enter image description here

有一个参数: 在 SwiftUI 中使用 listRowBack () ,但是如果直接使用 List 来迭代数据集合,那么它就无法工作。

这是我的解决办法:

    List {
// To make the background transparent, we have we use a ForEach as a wrapper
ForEach(files) {file in
Label(
title: { Text(file.name ?? fileOptionalFiller).lineLimit(listRowTextLineLimit) },
icon: { AppIcon.doc.foregroundColor(.primary) }
)
}
.listRowBackground(Color.primary.colorInvert())
}

基本上,如果在 List 内部使用 ForEvery,listRowBacking()就可以工作。

如果有人来这里寻找解决方案,在 iPhone X/11的风景不全宽:

.listRowBackground(Color("backgroundColour").edgesIgnoringSafeArea(.all))

Xcode Version 12.4

背景资料属性对我有用,但是必须使用 不透明。 没有 不透明就不是工作。

List {
ForEach(data, id: \.id) { (item) in
ListRow(item)
.environmentObject(self.data)
}
}
.background(Color.black)
.opacity(0.5)
struct Details: View {


var body: some View {
Spacer().overlay(
List {
Text("Hello World!").font(.title2)
.listRowBackground(Color.clear)
Text("Hello World again").font(.title2)
.listRowBackground(Color.clear)
}.onAppear() {
UITableView.appearance().backgroundColor = UIColor.green
UITableViewCell.appearance().backgroundColor = UIColor.green
}
)
}
}

改变背景颜色

正如其他人提到的,更改 UITableView 背景将影响应用程序中的所有其他列表。

然而,如果你想要不同的背景颜色,你可以设置默认为 安全,并设置背景颜色的迅速视图如下:

List {
Text("Item 1")
Text("Item 2")
Text("Item 3")
}
// Ignore safe area to take up whole screen
.background(Color.purple.ignoresSafeArea())
.onAppear {
// Set the default to clear
UITableView.appearance().backgroundColor = .clear
}

您可能希望更早地设置表视图的外观,比如在 场景代理或 root 视图中,如下所示:

// SceneDelegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
      

    

guard let windowScene = scene as? UIWindowScene else {
print("Returning because screne does not exist")
return
            

}
    

// Set here
UITableView.appearance().backgroundColor = .clear
let contentView = ContentView()
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}




// Root App View
@main
struct ListBackgroundApp: App {
    

init() {
UITableView.appearance().backgroundColor = .clear
}
    

var body: some Scene {
WindowGroup {
ContentView()
}
}
}

Working Background Color Change

二零二二年

MacOS 解决方案

下面的代码使所有 List的背景颜色透明:

// Removes background from List in SwiftUI
extension NSTableView {
open override func viewDidMoveToWindow() {
super.viewDidMoveToWindow()
        

backgroundColor = NSColor.clear
if let esv = enclosingScrollView {
esv.drawsBackground = false
}
}
}

enter image description here

..........

..........

..........

下面的代码使所有的 TextEditor背景颜色透明:

extension NSTextView {
open override var frame: CGRect {
didSet {
backgroundColor = .clear
drawsBackground = true
}
}
}

在我看来,伊斯洛姆 · 阿里莫夫 https://stackoverflow.com/a/59970379/9439097给出的答案似乎是迄今为止最好的实现。

唯一的缺点是: 这也会改变应用程序中所有其他列表视图的背景颜色,所以你需要手动将它们改回来,除非你想在所有地方都使用相同的颜色。

下面是一个示例视图:

import SwiftUI


struct TestView1: View {
    

init(){
UITableView.appearance().backgroundColor = UIColor(Color.clear)
}
    

@State var data = ["abc", "def"]
    

var body: some View {
VStack {
List {
ForEach(data, id: \.self) {element in
Text("\(String(describing: element))")
}
.background(Color.green)
.listRowBackground(Color.blue)
                

}
.background(Color.yellow)
Spacer()
Color.red
}
}
}


struct TestView1_Previews: PreviewProvider {
static var previews: some View {
TestView1()
}
}

生产:

如果希望避免全局设置所有表视图的外观,可以将 UITableView.appearance(whenContainedInInstancesOf:)UIHostingController组合起来。感谢 丹斯基尔的评论,你留下上面指出这一点。我是这么用的:

public class ClearTableViewHostingController<Content>: UIHostingController<Content> where Content: View {
public override func viewDidLoad() {
UITableView.appearance(whenContainedInInstancesOf: [ClearTableViewHostingController<Content>.self]).backgroundColor = .clear
}
}

你可以这样使用 ClearTableViewHostingController:

let view = MyListView()
let viewController = ClearTableViewHostingController(coder: coder, rootView: view)

然后在你的视图中你可以像这样设置列表背景颜色:

List {
Text("Hello World")
}
.background(Color.gray)

只需在 init()方法中添加 UITableView外观背景色并添加列表样式 (.listStyle(SidebarListStyle())。不要忘记导入 UIKit模块

struct HomeScreen: View {
init() {
UITableView.appearance().backgroundColor = .clear
}


let tempData:[TempData] = [TempData( name: "abc"),
TempData( name: "abc"),
TempData( name: "abc"),
TempData( name: "abc")]


var body: some View {
ZStack {
Image("loginBackgound")
.resizable()
.scaledToFill()
List{
ForEach(tempData){ data in
Text(data.name)
}
}
.listStyle(SidebarListStyle())
        

}
.ignoresSafeArea(edges: .all)
}
}

扩展列表如下:

extension List{
@available(iOS 14, *)
func backgroundList(_ color: Color = .clear) -> some View{
UITableView.appearance().backgroundColor = UIColor(color)
return self
}

}

使用 外观() . 背景色不太好的想法,因为它改变了所有表的背景颜色。我找到了一个工作的解决方案,颜色变化的确切表你在 IOS 14,15选择。

我们将使用一个需要在 List 中应用的修饰符来更改颜色

extension View {
    

func backgroundTableModifier(_ color: UIColor? = nil) -> some View {
self.modifier(BackgroundTableModifier(color: color))
}


}

我们的任务是找到 UITableView,然后改变颜色。

private struct BackgroundTableModifier: ViewModifier {
    

private let color: UIColor?
@State private var tableView: UITableView?
    

init(color: UIColor?) {
self.color = color
}
    

public func body(content: Content) -> some View {
if tableView?.backgroundColor != color {
content
.overlay(BackgroundTableViewRepresentable(tableBlock: { tableView in
tableView.backgroundColor = color
self.tableView = tableView
}))
} else {
content
}
}
}


private struct BackgroundTableViewRepresentable: UIViewRepresentable {
    

var tableBlock: (UITableView) -> ()
    

func makeUIView(context: Context) -> BackgroundTableView  {
let view = BackgroundTableView(tableBlock: tableBlock)
return view
}
    

func updateUIView(_ uiView: BackgroundTableView, context: Context) {}
}


class BackgroundTableView: UIView {
    

var tableBlock: (UITableView) -> ()
    

init(tableBlock: @escaping (UITableView) -> ()) {
self.tableBlock = tableBlock
super.init(frame: .zero)
}
    

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

override func layoutSubviews() {
super.layoutSubviews()
if let tableView = findTableView(in: self) {
tableBlock(tableView)
}
}
    

private func findTableView(in view: UIView) -> UITableView? {
if let tableView = view as? UITableView {
return tableView
}
        

if let superView = view.superview {
return findTableView(in: superView)
}
        

return nil
}
    

}

为了找到 UITableView,修饰符必须在 List 中。当然,您需要确保修饰符只被调用一次,而不需要将其应用到每一行。下面是一个用法的例子

List {
rows()
.backgroundTableModifier(.clear)
}


func rows() -> some View {
ForEach(0..<10, id: \.self) { index in
Row()
}
}

您可以使用 Github 中的 introspect库为底层表视图设置背景颜色,如下所示:

List { ... } .introspectTableView { tableView in
tableView.backgroundColor = .yellow
}

由于某些原因,颜色更改不起作用,您可以尝试将.listStyle 设置为

密码:

struct ContentView: View {
var body: some View {
VStack {
Text("Test")


List {
ForEach(1 ..< 4) { items in
Text(String(items))
}
}
.listStyle(.plain)
}
}

IOS16提供了一个修饰符来控制 List (和其他可滚动视图)的背景可见性: 背景(_:)

你可以通过 .hidden隐藏标准的系统背景。如果你也提供一个 background,这将变得可见。

List {
Text("One")
Text("Two")
}
.background(Image("MyImage"))
.scrollContentBackground(.hidden)

您可能还需要自定义列表行的背景(单个单元格)和分隔符。可以这样做:

List {
Section("Header") {
Text("One")
Text("Two")
.listRowBackground(Color.red)
}
.listRowBackground(Color.clear)
.listRowSeparator(.hidden)
}
.scrollContentBackground(.hidden)

In iOS 16, we got a native way to do this via 滚动内容背景 modifier.

通过将颜色(ShapeStyle)设置为 scrollcontentbackground,您可以选择 改变颜色

List {
Text("Item 1")
Text("Item 2")
Text("Item 3")
}
.scrollContentBackground(Color.pink)

Or you can hide the background .scrollContentBackground(.hidden) and set a custom one with .backgroud modifier.

List {
Text("Item 1")
Text("Item 2")
Text("Item 3")
}
.background {
Image("ventura")


}
.scrollContentBackground(.hidden)