我使用ForEach
来显示数组的内容,然后通过判断元素索引手动显示每个元素之间的分隔符.这是我的代码:
struct ContentView: View {
let animals = ["Apple", "Bear", "Cat", "Dog", "Elephant"]
var body: some View {
VStack {
/// array of tuples containing each element's index and the element itself
let enumerated = Array(zip(animals.indices, animals))
ForEach(enumerated, id: \.1) { index, animal in
Text(animal)
/// add a divider if the element isn't the last
if index != enumerated.count - 1 {
Divider()
.background(.blue)
}
}
}
}
}
结果:
这是可行的,但我希望有一种方法可以自动在任何地方添加除数,而不必每次都写Array(zip(animals.indices, animals))
.以下是我目前掌握的情况:
struct ForEachDividerView<Data, Content>: View where Data: RandomAccessCollection, Data.Element: Hashable, Content: View {
var data: Data
var content: (Data.Element) -> Content
var body: some View {
let enumerated = Array(zip(data.indices, data))
ForEach(enumerated, id: \.1) { index, data in
/// generate the view
content(data)
/// add a divider if the element isn't the last
if let index = index as? Int, index != enumerated.count - 1 {
Divider()
.background(.blue)
}
}
}
}
/// usage
ForEachDividerView(data: animals) { animal in
Text(animal)
}
这非常有效,隔离了所有样板zip
代码,仍然得到相同的结果.然而,这只是因为animals
是一个String
的数组,它符合Hashable
-如果我的数组中的元素不符合Hashable
,它将不起作用:
struct Person {
var name: String
}
struct ContentView: View {
let people: [Person] = [
.init(name: "Anna"),
.init(name: "Bob"),
.init(name: "Chris")
]
var body: some View {
VStack {
/// Error! Generic struct 'ForEachDividerView' requires that 'Person' conform to 'Hashable'
ForEachDividerView(data: people) { person in
Text(person.name)
}
}
}
}
这就是为什么SwiftUI的ForEach
附带了一个附加的初始值设定项init(_:id:content:)
,该初始值设定项采用自定义密钥路径来提取ID.我想在ForEachDividerView
中利用这个初始值设定项,但我想不出来.以下是我try 的内容:
struct ForEachDividerView<Data, Content, ID>: View where Data: RandomAccessCollection, ID: Hashable, Content: View {
var data: Data
var id: KeyPath<Data.Element, ID>
var content: (Data.Element) -> Content
var body: some View {
let enumerated = Array(zip(data.indices, data))
/// Error! Invalid component of Swift key path
ForEach(enumerated, id: \.1.appending(path: id)) { index, data in
content(data)
if let index = index as? Int, index != enumerated.count - 1 {
Divider()
.background(.blue)
}
}
}
}
/// at least this part works...
ForEachDividerView(data: people, id: \.name) { person in
Text(person.name)
}
我try 使用appending(path:)
将第一个键路径(从enumerated
中提取元素)与第二个键路径(从元素中获取Hashable
属性)组合起来,但得到了Invalid component of Swift key path
.
如何在ForEach
的元素之间自动添加分隔符,即使元素不符合Hashable
?