SwiftUI中List Mac OS的背景颜色

10

我正在使用 Mac OS 中的 ListView。我正在尝试更改该 ListView 的背景颜色。但是,这并不像预期的那样容易。

我尝试在 ListView 上使用 .background(Color(.red)) 属性。但那没有改变任何东西。

我只能找到 .listRowBackground(Color(.red)) 这个属性对表格行有影响。但是,其他背景并没有受到影响。

我准备了一个小演示来展示:

在我的视图主体中:

  VStack
    {
        List()
        {
            Text("Test")
                .listRowBackground(Color.green)

            Text("Test")
                .listRowBackground(Color.green)

            Text("Test")
                .listRowBackground(Color.green)

        }.background(Color(.red))

    }.background(Color(.red))

这是我得到的结果:

在此输入图片描述

主背景没有改变。我看过一个解决方案,可以更改UITableView.appearance,但对于我在Mac OS上使用SwiftUI来说不可行。

提前感谢。

4个回答

25
更新2:我没有验证过,但user1046037说有一个新的API可用于更改滚动背景:scrollContentBackground更新1:我发现了一种更好的方法来删除列表的背景而不影响整个应用程序:使用Introspect
import Introspect
import SwiftUI

extension List {
  /// List on macOS uses an opaque background with no option for
  /// removing/changing it. listRowBackground() doesn't work either.
  /// This workaround works because List is backed by NSTableView.
  func removeBackground() -> some View {
    return introspectTableView { tableView in
      tableView.backgroundColor = .clear
      tableView.enclosingScrollView!.drawsBackground = false
    }
  }
}

使用方法:

List {
  ForEach(items) { item in
    ...
  }
}.removeBackground()

旧回答:

@Asperi的回答是有效的,但仅在调整窗口大小之前。这里有另一种解决方法来覆盖List的颜色:

extension NSTableView {
  open override func viewDidMoveToWindow() {
    super.viewDidMoveToWindow()

    backgroundColor = NSColor.clear
    enclosingScrollView!.drawsBackground = false
  }
}

潜在的不利影响是该操作将影响应用中的所有列表。

很棒的答案!你可以把列表后面加上背景吗?非常感谢! - Oscar Franco
Introspect工作得很好,但是你可以看到背景正在被移除。它会在几秒钟内可见。 - davidev
我认为在SwiftUI中无法更改这个非常愚蠢。有没有想法在macOS Monterey中是否可以解决?LazyVStackForEach不是List的替代品(因为缺少选择和使用箭头键导航)。 - Lupurus
内省方法有时候有效,有时候无效。你们有相同的经历吗? - neptunes
非常感谢,我花了好几个小时才破解成功!:D - Sabesh Bharathi
显示剩余2条评论

4

第一张图片展示了问题的来源 - 使用的滚动视图默认是不透明的,所以添加的背景颜色存在但看不见。

demo1

解决方案是找到该滚动视图并禁用绘制背景。

demo2

以下是可能的解决方法或解决办法(但有效,因为所有修改都是通过 AppKit API 进行的,没有硬编码)。实际上,它与在 XIB 中为包含表格视图的滚动视图关闭复选框的操作相同。已测试使用 Xcode 11.2 / macOS 10.15。

struct ScrollViewCleaner: NSViewRepresentable {
    
    func makeNSView(context: NSViewRepresentableContext<ScrollViewCleaner>) -> NSView {
        let nsView = NSView()
        DispatchQueue.main.async { // on next event nsView will be in view hierarchy
            if let scrollView = nsView.enclosingScrollView {
                scrollView.drawsBackground = false
            }
        }
        return nsView
    }
    
    func updateNSView(_ nsView: NSView, context: NSViewRepresentableContext<ScrollViewCleaner>) {
    }
}

extension View {
    func removingScrollViewBackground() -> some View {
        self.background(ScrollViewCleaner())
    }
}

struct TestListBackground: View {
    var body: some View {
            List()
            {
                ForEach(0..<3) { _ in
                    Text("Test")
                        .listRowBackground(Color.green)
                }
                .removingScrollViewBackground() // must be called _inside_ List
                .background(Color.blue)
            }.background(Color.red)
    }
}

谢谢你的回答。视图的可视化效果非常棒。我以为有一个默认的背景,但不知道如何清除它。我很快会尝试这个答案。谢谢! - davidev
天啊,这太复杂了,非常感谢你的答案! - Oscar Franco
一开始我以为这个程序完美无缺,但是现在列表的颜色偶尔会出现问题,有没有其他方法可以解决这个问题? - Oscar Franco
3
当窗口被调整大小时,背景立即被重置。是否有解决方法? - Saket

3
Xcode 14Swift 5)中,您可以这样做:
 List {
 ...
 }
 .scrollContentBackground(.hidden)
 .background(.red)

这使ScrollView的背景变为透明,列表(List)的背景现在可以进行自定义。

enter image description here


scrollContentBackground() 可用于 iOS 16.0 和 macOS 13.0。 - isaced

3

很不幸,ListStyle协议没有文档记录,而.listStyle修饰符的使用范围非常有限,您可以从以下选项中选择:CarouselListStyle, DefaultListStyle, GroupedListStyle ,PlainListStyle, SidebarListStyle

尝试使用ScrollView和ForEach模拟List,这将为您提供很多灵活性,缺少的部分很容易编写。一旦ListStyle对开发人员可用,更改代码就会变得容易...

示例 enter image description here 源代码如下

struct ContentView: View {
    var body: some View {
        HStack(spacing: 0) {
            ScrollView {
                ForEach(0 ..< 4) { idx in
                    VStack(alignment: .leading) {
                        Divider().background(Color.blue)
                        Text("Test \(idx)")
                            .padding(.horizontal, 10)
                            .background(Color.pink)
                        //Divider()
                    }.padding(.bottom, -6)
                }
            }
                .frame(maxWidth: 100)
            .background(Color.gray)

            Color.green
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

谢谢帮助!我会尝试使用ScrollView。您是否有来自苹果公司的信息,开发者的下一个更新将什么时候推出? - davidev
ScrollView 不会回收项目,因此对于大量项目可能非常昂贵。 - Saket

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