如何获取动态列表/ForEach 可绑定元素的索引(新 Xcode 13 的语法)?
How to get the index of a dynamic List / ForEach bindable element (new Xcode 13's syntax)?
到目前为止,要在动态集合中的元素和列表的行之间设置绑定,我们必须这样做:
List(Array(zip(data.indices, data)), id: \.1.id) { index, _ in
HStack {
Text((index + 1).description)
TextField("", text: Binding(
get: { data[index].text },
set: { data[index].text = [=11=] }
))
}
}
我们需要:绑定元素的索引; + List
的元素标识符(避免奇怪的动画);和自定义 Binding
以避免在删除最后一行时崩溃。
这很复杂(而且我不确定它是否非常有效)。
自 WWDC21 以来,我们有了新的语法(可以反向部署):
List($data) { $item in
HStack {
Text("Index ?")
TextField("", text: $item.text)
}
}
更干净了。
但是虽然强烈建议使用这种新语法,但如果能够访问闭包中的元素索引就更好了。你知道我们怎么做吗?
编辑:
我试过这个(它有效),但我觉得这不是正确的方法:
let d = Binding(get: {
Array(data.enumerated())
}, set: {
data = [=13=].map {[=13=].1}
})
List(d, id: \.1.id) { $item in
HStack {
Text("\(item.0 + 1)")
TextField("", text: $item.1.text)
}
}
如果您的项目是 Equatable,您可以使用 firstIndex(of:)
获取它们的索引:
List($data) { $item in
HStack {
Text("Index \(data.firstIndex(of: item)! + 1)")
TextField("", text: $item.text)
}
}
您可以自己构建包装器:
struct ListIndexed<Content: View>: View {
let list: List<Never, Content>
init<Data: MutableCollection&RandomAccessCollection, RowContent: View>(
_ data: Binding<Data>,
@ViewBuilder rowContent: @escaping (Data.Index, Binding<Data.Element>) -> RowContent
) where Content == ForEach<[(Data.Index, Data.Element)], Data.Element.ID, RowContent>,
Data.Element : Identifiable,
Data.Index : Hashable
{
list = List {
ForEach(
Array(zip(data.wrappedValue.indices, data.wrappedValue)),
id: \.1.id
) { i, _ in
rowContent(i, Binding(get: { data.wrappedValue[i] }, set: { data.wrappedValue[i] = [=10=] }))
}
}
}
var body: some View {
list
}
}
用法:
ListIndexed($items) { i, $item in
HStack {
Text("Index \(i)")
TextField("", text: $item.text)
}
}
到目前为止,要在动态集合中的元素和列表的行之间设置绑定,我们必须这样做:
List(Array(zip(data.indices, data)), id: \.1.id) { index, _ in
HStack {
Text((index + 1).description)
TextField("", text: Binding(
get: { data[index].text },
set: { data[index].text = [=11=] }
))
}
}
我们需要:绑定元素的索引; + List
的元素标识符(避免奇怪的动画);和自定义 Binding
以避免在删除最后一行时崩溃。
这很复杂(而且我不确定它是否非常有效)。 自 WWDC21 以来,我们有了新的语法(可以反向部署):
List($data) { $item in
HStack {
Text("Index ?")
TextField("", text: $item.text)
}
}
更干净了。
但是虽然强烈建议使用这种新语法,但如果能够访问闭包中的元素索引就更好了。你知道我们怎么做吗?
编辑:
我试过这个(它有效),但我觉得这不是正确的方法:
let d = Binding(get: {
Array(data.enumerated())
}, set: {
data = [=13=].map {[=13=].1}
})
List(d, id: \.1.id) { $item in
HStack {
Text("\(item.0 + 1)")
TextField("", text: $item.1.text)
}
}
如果您的项目是 Equatable,您可以使用 firstIndex(of:)
获取它们的索引:
List($data) { $item in
HStack {
Text("Index \(data.firstIndex(of: item)! + 1)")
TextField("", text: $item.text)
}
}
您可以自己构建包装器:
struct ListIndexed<Content: View>: View {
let list: List<Never, Content>
init<Data: MutableCollection&RandomAccessCollection, RowContent: View>(
_ data: Binding<Data>,
@ViewBuilder rowContent: @escaping (Data.Index, Binding<Data.Element>) -> RowContent
) where Content == ForEach<[(Data.Index, Data.Element)], Data.Element.ID, RowContent>,
Data.Element : Identifiable,
Data.Index : Hashable
{
list = List {
ForEach(
Array(zip(data.wrappedValue.indices, data.wrappedValue)),
id: \.1.id
) { i, _ in
rowContent(i, Binding(get: { data.wrappedValue[i] }, set: { data.wrappedValue[i] = [=10=] }))
}
}
}
var body: some View {
list
}
}
用法:
ListIndexed($items) { i, $item in
HStack {
Text("Index \(i)")
TextField("", text: $item.text)
}
}