首页 > 解决方案 > 尝试在 SwiftUI 中实现类似列表的 View 类时使用类型泛型

问题描述

我正在寻找一个IndexedList可以像 SwiftUIList视图一样工作的工具,但它提供了一个(element, index) -> RowContent与当前(element) -> RowContent.

init()我还没有找到的一件事是,当您不知道类级别的类型时,如何将泛型分配给类实例。

如果您查看其中一个ListView init 签名,您会发现它使用了本地泛型:

 public init<Data, RowContent>(_ data: Data, selection: Binding<Set<SelectionValue>>?, @ViewBuilder rowContent: @escaping (Data.Element) -> RowContent) where Content == ForEach<Data, Data.Element.ID, HStack<RowContent>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable

但是,作为方法级别Data的泛型类型init(),您如何在类级别定义它以便您可以做到self.data = data

试过DataRandomAccessCollection

struct IndexedList<SelectionValue, Content>: View where SelectionValue: Hashable, Content: View {
  let data: RandomAccessCollection // <- type issue
  let selection: Binding<Set<SelectionValue>>?
  let rowContent: (Data.Element) -> View // <- type issue
  var body: some View {
    let withIndex = self.data.enumerated().map({ $0 })
    return List(withIndex, id: \.element.id) { index, element in
      self.rowContent(index, element)
    }
  }
  public init<Data, RowContent>(_ data: Data, selection: Binding<Set<SelectionValue>>?, @ViewBuilder rowContent: @escaping (Data.Element, index: number) -> RowContent) where Content == ForEach<Data, Data.Element.ID, HStack<RowContent>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable {
    self.data = data
    self.selection = selection
    self.rowContent = rowContent
  }
}

但它不起作用!

标签: swiftswiftui

解决方案


将您的要求移至类型,您无需费心约束初始化程序。

struct IndexedList<
  Data: RandomAccessCollection,
  SelectionValue: Hashable,
  HStackContent: View
>: View
where Data.Element: Hashable & Identifiable {
  typealias Selection = Binding< Set<SelectionValue> >?
  typealias RowContent =
    (EnumeratedSequence<[Data.Element]>.Element)
    -> ForEach< Data, Data.Element.ID, HStack<HStackContent> >

  let data: Data
  let selection: Selection
  let rowContent: RowContent

  var body: some View {
    List(
      Array( data.enumerated() ),
      id: \.element,
      rowContent: rowContent
    )
  }

  public init(
    _ data: Data,
    selection: Selection,
    @ViewBuilder rowContent: @escaping RowContent
  )  {
    self.data = data
    self.selection = selection
    self.rowContent = rowContent
  }
}

推荐阅读