我有一个SwiftUI父视图,它在导航堆栈上推送一个细节视图。详细视图绑定到父视图上的某些数据。
根据设置的不同,在局部视图中,数据更改时发生的某些动画会被打断。SwiftUI中损坏的动画不仅丑陋,而且可能指向可能导致渲染性能的更深层次问题(请参阅https://developer.apple.com/wwdc21/10022)。
具体而言,该问题仅在以下情况下发生:
- 我传递一个绑定到
ObservableObject
上的一些数据;* 和 * - 详细视图被推到
NavigationStack.
上
它对所有其他情况都能正常工作。
我发现了一个解决方法,将ObservableObject
传递给子视图,而不是绑定到data属性。然而,我不认为这是一个可行的解决方案,因为它是一个架构上的妥协,将不需要的信息暴露给细节视图(还有其他原因)。
这里是一个最小的可重复的例子。
import SwiftUI
struct SpaceProbe {
// let id: UUID = UUID() // does not help
let name: String
var launched: Bool = false
}
class SpacePort: ObservableObject {
@Published var probe: SpaceProbe = SpaceProbe(name: "Psyche", launched: true)
}
struct ContentView: View {
@StateObject var spacePort: SpacePort = SpacePort()
@State var probe: SpaceProbe = SpaceProbe(name: "Psyche", launched: true)
var body: some View {
NavigationStack {
List {
Section(header: Text("State:")) {
NavigationLink {
Cell(probe: $probe)
.padding()
} label: {
Text("Details (works)")
}
Cell(probe: $probe)
}
Section(header: Text("State Object:")) {
NavigationLink {
Cell(probe: $spacePort.probe)
.padding()
} label: {
Text("Details (broken animation)")
}
NavigationLink {
ObjectCell(spacePort: spacePort)
.padding()
} label: {
Text("Details (works but bad architecture)")
}
Cell(probe: $spacePort.probe)
}
}
.navigationBarTitle("Space Probe")
}
}
}
struct Cell: View {
@Binding var probe: SpaceProbe
var body: some View {
VStack(alignment: probe.launched ? .trailing : .leading) {
HStack {
Text(probe.name)
Spacer()
Button(probe.launched ? "Cancel" : "Launch") {
Task { @MainActor in
withAnimation {
probe.launched.toggle()
}
}
}
}
Text("🛰️").font(.system(size: 40))
.padding()
}
}
}
struct ObjectCell: View {
@ObservedObject var spacePort: SpacePort
var body: some View {
VStack(alignment: spacePort.probe.launched ? .trailing : .leading) {
HStack {
Text(spacePort.probe.name)
Spacer()
Button(spacePort.probe.launched ? "Cancel" : "Launch") {
Task { @MainActor in
withAnimation {
spacePort.probe.launched.toggle()
}
}
}
}
Text("🛰️").font(.system(size: 40))
.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
我该怎么办?
1条答案
按热度按时间uajslkp61#
我不知道为什么会出现这个问题,但有一个简单的解决方法。
将
.animation
添加到Cell
中的VStack
: