如何解决使用更改项目数量更新 ForEach 的问题 - .count 似乎返回错误值
我创建了一个简单的视图,旨在显示存储在 Observable Object 属性中的数组的内容:
struct Satellite {
let name: String
let orbit: Double
let color: Color
}
class OrbitalSystem: ObservableObject{
@Published var objects: [Satellite] = []
}
struct OrbitalSystemView: View {
@Observedobject var orbitalSystem: OrbitalSystem
var body: some View{
vstack{
ForEach(0..<orbitalSystem.objects.count){ n in
HStack{
Text("\(orbitalSystem.objects[n].name)")
Spacer()
Text("\(orbitalSystem.objects[n].orbit,specifier: "%.2f")")
}
.padding()
.background(orbitalSystem.objects[n].color)
}.padding()
}
}
}
然后我想在 ContentView 中使用这个通用视图,但是在应用程序中,我使用的数据结构(struct Planet)与通用视图(struct Satellite)中使用的结构不同。为了保持所需的更改最少,我向 struct Planet 添加了一个计算属性,将 Planet 的内容转换为元素 Satellite。对 ContentView 中的行星数组进行任何更改后,属性观察者会将其转换为卫星数组并将其存储在 Observedobject 属性中。要在初始加载时更新视图,请使用 .onAppear 修饰符设置行星阵列。
struct Planet {
let name: String
let distancetoSun: Int
let surface: Color
var satellite : Satellite {
Satellite(name: self.name,orbit: Double(self.distancetoSun),color: self.surface)
}
}
struct ContentView: View {
@Observedobject var planetarySystem = OrbitalSystem()
@State private var planets: [Planet] = []{
didSet{
var objects = [Satellite]()
for planet in planets {
objects.append(planet.satellite)
}
planetarySystem.objects = objects
}
}
var body: some View {
OrbitalSystemView(orbitalSystem: planetarySystem)
.onAppear{
planets = [
Planet(name: "Mercury",distancetoSun: 1,surface: Color.orange),Planet(name: "Venus",distancetoSun: 2,surface: Color.gray),Planet(name: "Earth",distancetoSun: 3,surface: Color.blue),Planet(name: "Mars",distancetoSun: 4,surface: Color.red)
]
}
}
}
这段代码在原理上是有效的,但有一个非常奇怪的行为。我的预期结果是:A Stack of four lines listing: Mercury 1.00,Venus 2.00,Earth 3.00,Mars 4.00 with different colors in the background
但是使用上面的代码,我得到了一个空视图。我通过像这样修改 OrbitalSystem 类得到了预期的结果:
class OrbitalSystem: ObservableObject{
@Published var objects: [Satellite] = [
Satellite(name: "",orbit: 0,color: Color.white),Satellite(name: "",color: Color.white)
]
}
如果
@Published var objects: [Satellite] = [
Satellite(name: "",color: Color.white)
]
改为这样,结果视图也只显示两行:Mercury 1.00 and Venus 2.00 with the respective background colors。
因此,即使数组的内容已更新,ForEach(0.. 我使用的是 Xcode 12.3 如果您对此行为做出任何澄清,我将不胜感激。谢谢
解决方法
如果您的数据是动态的(当视图在屏幕上时会发生变化),您需要为每个项目提供一个 ID,以便视图知道何时更新。
方法 1:您可以通过更改 ForEach 循环为其指定本地 ID:
VStack{
ForEach(orbitalSystem.objects.indices,id: \.self) { n in
HStack{
Text("\(orbitalSystem.objects[n].name)")
Spacer()
Text("\(orbitalSystem.objects[n].orbit,specifier: "%.2f")")
}
.padding()
.background(orbitalSystem.objects[n].color)
}.padding()
}
方法 2:您可以使 Satellite 符合 Identifiable 并在您 init() 项目时为每个项目提供自己的 ID。在这里,您可以根据需要自定义 ID,并且 ForEach 不需要循环索引,而是循环对象本身。
-
使卫星符合可识别性。
struct Satellite: Identifiable { let id = UUID() let name: String let orbit: Double let color: Color }
-
更新每个循环
VStack{ ForEach(orbitalSystem.objects) { object in HStack{ Text("\(object.name)") Spacer() Text("\(object.orbit,specifier: "%.2f")") } .padding() .background(object.color) }.padding() }
如果您查看 ForEach 的不同 init 方法,您会注意到 Range<Int>
方法“在给定的恒定范围内按需计算”视图。因此,您需要对动态数据使用其他初始化之一。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。