如果我有这样的东西:
struct ContentView: View {
var results = [Result(score: 8), Result(score: 5), Result(score: 10)]
var body: some View {
VStack {
ForEach(results, id: \.id) { result in
Text("Result: \(result.score)")
}
}
}
}
然后我有一个按钮,该按钮将sometihng附加到结果数组,整个ForEach循环将重新加载。这是有道理的,但我想知道是否有某种方法可以防止这种情况。我问的原因是因为我有一个ForEach循环,其中包含一些项目,每个项目都播放一个动画。但是,如果将另一个项目附加到数组,则新项目将出现在ForEach的顶部,但是由于重新加载了整个视图,因此项目中播放的其他动画将停止。
有什么办法可以防止这种情况?是否想将项目添加到ForEach数组中并显示出来,但不重新加载整个 ForEach循环?
我认为没有,但是我想知道如何解决这个问题。
答案 0 :(得分:2)
创建单独的视图来迭代ForEach
内容,然后SwiftUI呈现引擎将更新容器(通过添加新项),但不会刷新现有行
ForEach(results, id: \.id) {
ResultCellView(result: $0)
}
和
struct ResultCellView: View {
let result: Result
var body: some View {
Text("Result: \(result.score)")
}
}
注意:我看不到您的模型,因此可能需要将其确认为Hashable,Equatable。
答案 1 :(得分:1)
通常,不提供id
会使ForEach
无法知道更改了什么(因为它没有项目的跟踪),因此不会重新呈现视图。
例如
struct ContentView: View {
@State var myData: Array<String> = ["first", "second"]
var body: some View {
VStack() {
ForEach(0..<self.myData.count) { item in
Text(self.myData[item])
}
Button(action: {
self.myData.append("third")
}){
Text("Add third")
}
}
}
}
这会抛出一个控制台输出(您可以忽略),它告诉您我刚刚在上面写的内容:
ForEach<Range<Int>, Int, Text> count (3) != its initial count (2).
`ForEach(_:content:)` should only be used for *constant* data.
Instead conform data to `Identifiable` or use `ForEach(_:id:content:)`
and provide an explicit `id`!
对于您的代码,请尝试以下操作: 在iOS 13.5上进行了测试。
struct ContentView: View {
@State var results = [Result(score: 8), Result(score: 5), Result(score: 10)]
var body: some View {
VStack {
ForEach(0..<self.results.count) { item in
// please use some index test on production
Text("Result: \(self.results[item].score)")
}
Button(action: {
self.results.append(Result(score: 11))
}) {
Text("Add 11")
}
}
}
}
class Result {
var score: Int
init(score: Int) {
self.score = score
}
}
请注意,这是一个“ hacky”解决方案,ForEach
不适用于此类情况。 (请参阅控制台输出)