列表Mac OS的SwiftUI背景颜色

时间:2020-02-28 15:28:13

标签: swift macos swiftui

我在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))

那是我得到的结果:

enter image description here

主要背景不变。我读到有关更改UITableView.appearance的解决方案的信息,但对于Mac OS的SwiftUI,这对我来说是不可能的。

预先感谢

3 个答案:

答案 0 :(得分:7)

更新:我找到了一种更好的方法来删除列表背景,而又不影响整个应用程序:使用Introspect

import Introspect

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's answer有效,但仅在调整窗口大小之前有效。这是替代List颜色的另一种解决方法:

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

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

潜在的缺点是,这将影响应用程序中的所有列表。

答案 1 :(得分:3)

第一张图片显示了问题的根源-所使用的滚动视图默认情况下是不透明的,因此添加的彩色背景在那里但不可见

demo1

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

demo2

这里是解决此问题或解决方法的一种可能方法(但由于所有修改都是通过AppKit API进行的,因此无需硬编码即可有效)。实际上,这与关闭XIB中用于持有我们的tableview的scrollview的复选框相同。在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)
    }
}

答案 2 :(得分:1)

很遗憾,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)
    }
}