首页 > 解决方案 > 如何定义一个接受任意数据元素并产生“一些”视图的闭包?

问题描述

我正在构建一个显示字符串集合的自定义视图,但希望将其扩展为接受一个闭包,该闭包将以不同的方式呈现这些字符串中的每一个,可能不是作为Text视图。例如,这是我的原始代码:

struct MyCollectionView : View {
  var data : [String]
  var body : some View {
    ZStack {
      ForEach(0..<data.count, id: \.self) { string in
        Text(string) // <- will try to invoke the closure here
      }
    }
  }
}

但是现在我想注入一个“renderer”闭包,它将接受一个字符串并产生一个视图,如下所示:

struct MyCollectionView : View {
  typealias CellRenderer = (String)->View
  var cellRenderer : CellRenderer = { string in // compiler error on CellRenderer: "Protocol 'View' 
    // can only be used as a generic constraint because it has Self or associated type requirements"
    Text(string)
  } // default implementation
  var data : [String]
  var body : some View {
    ZStack {
      ForEach(0..<data.count, id: \.self) { string in
        self.cellRenderer(string) // <- trying to invoke the cell renderer
      }
    }
  }
}

我怎样才能宣布这种关闭?也许它不应该是一个闭包,而是一个将产生some View给定字符串的对象。

标签: swiftui

解决方案


这是一种可能的方法。适用于 Xcode 11.2、iOS 13.2。

struct MyCollectionView<Data, Cell>: View where Data: Hashable, Cell: View {
    typealias CellRenderer = (Data) -> Cell
    var data : [Data]
    var cellRenderer : CellRenderer


    init(_ data: [Data], @ViewBuilder cellRenderer: @escaping CellRenderer) {
        self.data = data
        self.cellRenderer = cellRenderer
    }

    var body : some View {
        ZStack {
            ForEach(data, id: \.self) { value in
                self.cellRenderer(value)
            }
        }
    }
}


struct MyCollectionView_Previews: PreviewProvider {
    static var previews: some View {
        MyCollectionView(["one", "two"]) { value in
            Text(value)
        }
    }
}

推荐阅读