我有以下组件来呈现半透明字符的网格:
var body: some View {
VStack{
Text("\(self.settings.numRows) x \(self.settings.numColumns)")
ForEach(0..<self.settings.numRows){ i in
Spacer()
HStack{
ForEach(0..<self.settings.numColumns){ j in
Spacer()
// why do I get an error when I try to multiply i * j
self.getSymbol(index:j)
Spacer()
}
}
Spacer()
}
}
}
settings
是一个环境对象
每当更新settings
时,最外层VStack
中的文本都会正确更新。但是, View 的其余部分不会更新(网格的尺寸与以前相同)。这是为什么?
第二个问题:
为什么无法访问内部 ForEach
循环中的 i
并将其作为参数传递给函数?
我在外部 ForEach
循环处收到错误:
Generic parameter 'Data' could not be inferred
最佳答案
TL;DR
您的 ForEach 需求 id: \.self
添加在您的范围之后。
说明
ForEach 有 several initializers 。您正在使用
init(_ data: Range<Int>, @ViewBuilder content: @escaping (Int) -> Content)
哪里data
必须是一个常数。
如果您的范围可能会发生变化(例如,您正在从数组中添加或删除项目,这将更改上限),那么您需要使用
init(_ data: Data, id: KeyPath<Data.Element, ID>, content: @escaping (Data.Element) -> Content)
您提供 id
的键路径参数,它唯一标识 ForEach
的每个元素循环过去。在 Range<Int>
的情况下,您要循环的元素是 Int
指定数组索引,该索引是唯一的。因此您可以简单地使用\.self
keypath 让 ForEach 通过它自己的值来识别每个索引元素。
实际情况如下:
struct ContentView: View {
@State var array = [1, 2, 3]
var body: some View {
VStack {
Button("Add") {
self.array.append(self.array.last! + 1)
}
// this is the key part v--------v
ForEach(0..<array.count, id: \.self) { index in
Text("\(index): \(self.array[index])")
//Note: If you want more than one views here, you need a VStack or some container, or will throw errors
}
}
}
}
如果你运行它,你会看到当你按下按钮将项目添加到数组时,它们将出现在 VStack
中自动地。如果删除“id: \.self
”,您将看到原始错误:
`ForEach(_:content:)` should only be used for *constant* data.
Instead conform data to `Identifiable` or use `ForEach(_:id:content:)`
and provide an explicit `id`!"
关于swiftui - View 不会在嵌套 ForEach 循环中重新呈现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58504575/