如何在SwiftUI中修改列表的背景颜色?

134

我正在尝试使用SwiftUI重新创建我之前用UIKit构建的用户界面,但是我遇到了一些小问题。

我想要更改这里 List 的颜色,但是似乎没有任何属性能按照我的期望工作。以下是示例代码:

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

我想改变白色区域


这对我有用。将其添加到我的ContentView_Previews中。当您使用List时,请确保顶部的任何堆栈都在顶部具有spacer。.edgesIgnoringSafeArea(.all) 喜欢调皮捣蛋。 - Alias111
在另一个答案的帮助下,我能够像您的屏幕截图一样以不同的方式为列表中的每个元素着色。https://dev59.com/CVMI5IYBdhLWcg3wUZyd#69514684 - charelf
对于任何未来的观众,这是 iOS 16 版本 https://dev59.com/ClEG5IYBdhLWcg3wI06g#72650158 - Timmy
30个回答

163

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

struct TestRow: View {

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

然后在主体中:

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

这个功能运作得很好,但我仍然不知道如何删除行之间的分割线...


26
SwiftUI 现在非常不稳定,当我像这样使用代码并硬编码我的列表项时它可以正常工作。但是当我异步加载数据时,它就无法正常工作了。 - andromedainiative
2
是的,这有点麻烦。不过玩起来很有趣。希望很快会更加顺畅。 - Marius Waldal
2
@MariusWaldal 你找到如何更改部分视图背景颜色了吗? - Aliaksandr Bialiauski
4
@andromedainiative 的待办事项清单,使用以下代码可以使其正常工作:ForEach(items, id: .self) { item in Text(item).listRowBackground(Color.green) }。 - Steve Ham
1
我曾经遇到一个非常愚蠢的问题,就是.listRowBackground()修饰符必须在.contextMenu()修饰符之后,否则它将无法工作。Xcode 12.0.1 - Othyn
显示剩余2条评论

55

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

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

17
我要如何在不同的列表中进行变化?我将此应用于一个标签页中的一个列表,结果影响了另一个标签页中的另一个列表。 - glothais-kwl
很好,也可以使用:UITableView.appearance().separatorColor = .darkGray - MrAn3
1
@glothais-kwl,你找到“重置”TableView外观的方法了吗?像你一样,我希望在某些视图上实现这个功能,而不是所有视图,并且需要一种基于显示的视图来重置它的方法。 - Learn2Code
很气愤这样一个重要的改变(否则你的列表将漂浮在白色背景上)如此脱离上下文而难以访问。 也可以这样使用: List { }.onAppear{ UITableView.appearance().separatorStyle = .none UITableViewCell.appearance().backgroundColor = .green UITableView.appearance().backgroundColor = .green } - C. Hellmann
3
@glothais-kwl 你可以使用 UIAppearance.appearanceWhenContainedInInstancesOfClasses: 并且在其中传递一个 UIHostingController 的特定子类作为参数,以用于呈现当前的 SwiftUI 视图。 - DanSkeel

47

输入图像描述

struct ContentView: View {

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

    var body: some View {

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

1
它能够工作,但我仍然困在如何更改列表本身背景的问题上。 - Vladimir Amiorkov
23
这也是我使用的唯一有效方法。我认为强调必须使用 List { ForEach(elements) { }} 而不是 List(elements) { } 才能使这个修饰符起作用是很重要的。 - Przemyslaw Jablonski
7
令人不可思议的是,指定数据到列表的方式使这个修改器无法工作。看到SwiftUI内部存在这种错误并不会对SwiftUI有一个好的印象。 - Marchy
2
这个问题在iOS 15中已经得到解决。listRowBackground可以与List(elements)中的项目以及List { ForEach(elements) {一起使用。 - OliverD
@VladimirAmiorkov 如果列表样式为.plain,您可以更改列表的背景。 - Gavin Morrow
这会移除选中行时的颜色变化。你知道如何保留它吗? - Gianni

33

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

UITableView.appearance().backgroundColor = UIColor.clear

只需将此行代码放置在AppdelegatedidFinishLaunchingWithOptions方法中。 用所需的颜色替换UIColor.clear,以添加到list的背景颜色中。


1
它能够工作,但是它不能移除实际显示的行下面的白色背景。 - Michał Ziobro
4
它能够完成任务:UITableViewCell.appearance().backgroundColor = .clear。 - Michał Ziobro
这个问题在 Mac 上有解决方案吗? - davidev
@davidev 我下面的回答 - Andrew_STOP_RU_WAR_IN_UA

30

iOS 16提供了一种修饰符来控制列表(和其他可滚动视图)的背景可见性:scrollContentBackground(_:)

您可以通过.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)

24

更改背景颜色

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

但是,如果您想要不同的背景颜色,您可以将默认设置为clear,并在SwiftUI视图中设置背景颜色,如下所示:

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
}

您可能希望在SceneDelegate或根视图中更早地设置tableview的外观,例如:

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

工作背景色更改


将backgroundColor设置为clear的技巧,甚至让您可以使用图像作为背景!非常感谢。 - Jon Malachowski

18

2022

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

2
太棒了!SwiftUI 应该成为默认选项,哈哈。 - arthas
天哪,你可以在扩展中重写吗? - Peter Lapisu
@PeterLapisu,你看到了吗 :) 嘿嘿嘿 - Andrew_STOP_RU_WAR_IN_UA

16

有一个论点:SwiftUI中的listRowBackground(),但是如果你直接使用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 中使用 ForEach 时,listRowBackground() 才能正常工作。


12

我使用 colorMultiply(Color:) 函数可以改变整个列表的颜色。只需在列表视图末尾添加此修饰符,然后填充将会将表格推到设备边缘。例如:

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

如何通过着色、去饱和度等方式调整视图


9
它可以使用,但会影响单元格的颜色 - 比如刚试了红色文本作为列表项 - 它们变成黑色了。 - Matteo Pacini
1
是的,不幸的是,混合不是你想要的。你希望它是分层的,背景视图颜色作为背景,然后单元格颜色和/或文本颜色在其上方。 - Marius Waldal

11

我不知道这之间有什么联系,但如果你用Form包装列表,它就可以工作。

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

4
正如Caleb所指出的,listRowBackground应该应用于列表项本身而不是整个列表。此外,你可以直接使用Color("Primary")而无需强制解包UIColor :) - CMash
这个可以运行,但是我在列表中有一个部分标题,而该标题现在不再“粘性”——它随着列表一起移动:(。 - Chris Prince

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