我有一个foreach我添加和删除项目,但是我正在遇到lazyvstack的动画问题。
LAZYVSTACK重复使用视图,因此,当我删除项目并在同一索引中添加新项目时,SwiftUi将其视为相同的视图,并且不播放插入动画。
为了强制动画,我更新了LazyvStack的ID(LazyID),但这会导致所有项目重新渲染,这效率低下。
我希望动画在添加/删除项目时可以正常工作,而无需触发现有视图的完整重新渲染。
根问题:
LazyvStack通过重复使用视图来优化渲染。
删除项目后,SwiftUI不会立即完全对其进行分解。
当将新项目插入相同的索引时,Swiftui重复了旧视图,跳过动画。
我需要什么:
使Swiftui识别出插入为真正的“新”项目的方法。
避免在LazyvStack上使用.ID(UUID())(迫使所有视图的重新呈现)。
防止LazyvStack在以前删除的索引中添加新项目时,以为它是重复使用旧视图的。
macos:[MacOS 15.2(24C101),Xcode 16.2]

import SwiftUI
struct ContentView: View {
@State private var items: [ItemType] = []
@State private var lazyID: UUID = UUID()
var body: some View {
VStack {
ScrollView {
LazyVStack(spacing: 5.0) {
ForEach(items) { item in
CircleView(item: item)
.transition(
.asymmetric(
insertion: .move(edge: .top),
removal: .move(edge: .top)
)
)
}
}
.id(lazyID)
.animation(Animation.linear , value: items)
}
.padding()
Spacer()
HStack {
Button("Append New Item") {
let newItem = ItemType(value: items.count + 1)
items.append(newItem)
}
Button("Remove last Item") {
if let last = items.popLast() {
print("Removed:", last.value)
} else {
print("Array is empty!")
}
// This will allow the animation to happen when adding a new item, but at the cost of re-rendering all views.
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(1000)) {
// lazyID = UUID()
}
}
}
}
.padding()
}
}
struct CircleView: View, Equatable {
let item: ItemType
var body: some View {
print("CircleView called for: " + String(describing: item.value))
return Circle()
.fill(Color.red)
.frame(width: 50.0, height: 50.0)
.overlay(Circle().stroke(lineWidth: 1.0))
.overlay(Text("\(item.value)").foregroundStyle(.white))
}
static func == (lhs: Self, rhs: Self) -> Bool {
(lhs.item.id == rhs.item.id)
}
}
struct ItemType: Identifiable, Equatable {
let id: UUID = UUID()
let value: Int
static func == (lhs: Self, rhs: Self) -> Bool {
(lhs.id == rhs.id)
}
}
swiftui,身份就是一切。在其数据模型中,Swiftui是一堆巨大的嵌套集合,需要扩散以检测身份变化并驱动动画。
当您这样做时:
struct ItemType: Identifiable, Equatable {
let id: UUID = UUID()
let value: Int
}
您在每个实例上为同一的新身份创建一个新的身份。