【问题标题】:macOS SwiftUI Table with more than 10 columns?超过 10 列的 macOS SwiftUI 表?
【发布时间】:2021-12-20 18:12:30
【问题描述】:

我尝试添加 Group {} 技巧以在 Table 视图中获取超过 10 个元素,但编译失败就像没有组的元素超过 10 个时一样。

    var body: some View {
      Table(viewModel.tableArrayOfStructs, sortOrder: $sortOrder) {
        Group {
          TableColumn("One", value: \.One).width(min: 35, ideal: 35, max:   60)
          TableColumn("Two", value: \.Two).width(30)
          TableColumn("Three", value: \.Three).width(50)
          TableColumn("Four", value: \.Four).width(min: 150, ideal: 200, max: nil)
          TableColumn("Five", value: \.Five).width(50)
          TableColumn("Six", value: \.Six).width(min: 50, ideal: 55, max: nil)
          TableColumn("Seven", value: \.Seven).width(88)
          TableColumn("Eight", value: \.Eight).width(88)
          TableColumn("Nine", value: \.Nine).width(20)
          TableColumn("Ten", value: \.Ten).width(50)
       }
       TableColumn("Eleven", value: \.Eleven).width(50)

    }

如果我将第 11+ 列也添加到新组中,我会遇到同样的问题。编译器报告:

The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

有没有什么方法可以让一个超过 10 列的表不下拉到 NSViewRepresentable?

【问题讨论】:

  • 是的,您的 Group 解决方案还可以,但整体对于编译器来说太复杂了。尝试添加显式类型或使用较小的函数构建它。它不必是视图主体的一部分。主体可以调用返回这些子视图的 var 或 func。
  • 谢谢。请注意,即使我删除了第 11 列,编译器仍然会对该组咳嗽,但如果我删除了该组并且只有 10 个项目就可以了。你有列变量的例子吗?我可以创建一个只返回 TableColumns 数组的函数吗?
  • 尝试使用这些宽度。可能是导致问题的原因。没怎么用过 Table,但感觉很像第 1 版。第 2 版有望更加强大,提供更多功能。
  • 尝试使用较小的组,例如 3 组,每组 4 人或其他。您还可以将组提取到变量中,这可以帮助编译器更快地找出类型。

标签: swift macos swiftui


【解决方案1】:

评论中要求的示例(未经测试)。

var body: some View {
  Table(viewModel.tableArrayOfStructs, sortOrder: $sortOrder) {
    Group {
      self.foo //since foo has the @VB annotation, these will just be “pasted” in here. 
    }
    self.foobar //not a @VB, so it returns a specific view
    self.bar(count: …)
 }

@ViewBuilder //not always necessary but usually very handy, depending on what you return
var foo: some View {
      TableColumn("One", value: \.One).width(min: 35, ideal: 35, max:   60)
      TableColumn("Two", value: \.Two).width(30)
      TableColumn("Three", value: \.Three).width(50)
      TableColumn("Four", value: \.Four).width(min: 150, ideal: 200, max: nil)
      TableColumn("Five", value: \.Five).width(50)
      TableColumn("Six", value: \.Six).width(min: 50, ideal: 55, max: nil)
      TableColumn("Seven", value: \.Seven).width(88)
      TableColumn("Eight", value: \.Eight).width(88)
      TableColumn("Nine", value: \.Nine).width(20)
      TableColumn("Ten", value: \.Ten).width(50)
   }

var foobar: some View {
  Group {
          TableColumn("One", value: \.One).width(min: 35, ideal: 35, max:   60)
          TableColumn("Two", value: \.Two).width(30)
          TableColumn("Three", value: \.Three).width(50)
  }
}

func bar(count: Int) -> some View
{
   //as with foo, return your sub view
   //annotate with @ViewBuilder if necessary
}

重点是,您不必在视图主体中构建整个视图。取决于编程风格、代码组织、语义……;将您的代码拆分为其他子视图结构或视图结构中的(私有)变量和函数。

【讨论】:

  • 谢谢。 TableColumn 不符合 View,所以 foo 变量无法编译。由于 Group,foobar 确实符合 View,但是在 TableColumns 周围添加 Group 会使编译器无法完成并出现相同的错误。除了 Table 文档中的基本示例之外,可能需要使用 TableColumnBuilder 来执行任何操作。遗憾的是,TableColumnBuilder 的示例很少,但参考文档看起来很完整。
【解决方案2】:

Apple 开发者技术支持能够提供帮助。他们建议在 TableColumn 中明确使用 value: type 信息,以便为编译器提供一些帮助。如果没有明确的类型信息,无论是否有组,编译器都会简单地放弃。我还发现,添加一个组后,您需要将所有 TableColumns 添加到组内(每组有 10 个或更少的 TableColums)

var body: some View {
  Table(viewModel.tableArrayOfStructs, sortOrder: $sortOrder) {
    Group {
      TableColumn("One", value: \ViewModel.TableArrayOfStructs.One).width(min: 35, ideal: 35, max:   60)
      TableColumn("Two", value: \ViewModel.TableArrayOfStructs.Two).width(30)
      TableColumn("Three", value: \ViewModel.TableArrayOfStructs.Three).width(50)
      TableColumn("Four", value: \ViewModel.TableArrayOfStructs.Four).width(min: 150, ideal: 200, max: nil)
      TableColumn("Five", value: \ViewModel.TableArrayOfStructs.Five).width(50)
      TableColumn("Six", value: \ViewModel.TableArrayOfStructs.Six).width(min: 50, ideal: 55, max: nil)
      TableColumn("Seven", value: \ViewModel.TableArrayOfStructs.Seven).width(88)
      TableColumn("Eight", value: \ViewModel.TableArrayOfStructs.Eight).width(88)
      TableColumn("Nine", value: \ViewModel.TableArrayOfStructs.Nine).width(20)
      TableColumn("Ten", value: \ViewModel.TableArrayOfStructs.Ten).width(50)
   }
   Group {
     TableColumn("Eleven", value: \ViewModel.TableArrayOfStructs.Eleven).width(50)
   }

}

【讨论】:

    【解决方案3】:

    非常感谢您提供使用 Group 的提示。我不确定它是否会像其他 View 一样在 TableColumn 上工作,但它可以工作。 就我而言,将所有表列包含在组中并不是强制性的。

    我还收到了来自 Apple 开发人员技术支持的提示,以明确说明值类型:\ViewModel.property 而不是 .property。

    我们也可以像这样使用计算属性来生成一个 TableColumn:

    var firstNameColumn: TableColumn<ViewModel, KeyPathComparator<ViewModel>, Text, Text> {
        TableColumn("Firstname", value: \ViewModel.firstname)
    }
    

    第一个 Text 引用自动生成文本的 \ViewModel.firstname,而第二个 Text 用于标签“FirstName”

    在某些情况下,当无法比较类型时,可以将 KeyPathComparator 替换为 Never。

    例如日期:

    var dateColumn: TableColumn<ViewModel, Never, DateView, Text> {
        TableColumn("Date") {doc in
            DateView(date: doc.date)
        }
    }
    

    其中 DateView 是自定义视图。

    希望对他人有所帮助

    问候

    文森特

    【讨论】: