绑定到 NavigationView 内的 StateObject 的 SwiftUI 动画问题

SwiftUI animation problem with a binding to a StateObject inside a NavigationView

关于 SwiftUI 中的动画,我有一个有趣的情况。在其简化形式中,我有一个显示矩形的视图,当点击该矩形时,它应该切换 Bool 绑定并用颜色的动画过渡表示变化。但是当视图位于 NavigationView 内时,动画似乎不会发生,绑定来自 StateObject 而不是简单的本地状态。我无法解释为什么会这样,如果有任何想法,我将不胜感激。

下面是显示重现问题的简化案例的代码。应用程序代码不是特别有趣;它是创建 WindowGroup 并在其中显示 ContentView 实例的默认代码。

import SwiftUI

class AppState: ObservableObject {
    @Published var isRed = false
}

struct RectView: View {
    @Binding var isRed: Bool

    var body: some View {
        Rectangle()
            .fill(isRed ? Color.red : Color.gray)
            .frame(width: 75, height: 75, alignment: .center)
            .onTapGesture {
                withAnimation(.easeInOut(duration: 1)) {
                    isRed.toggle()
                }
            }
    }
}

struct ContentView: View {
    @StateObject var appState = AppState()
    @State private var childViewIsRed = false

    var body: some View {
        VStack {
            NavigationView {
                List {
                    NavigationLink("Link with binding to state object", destination: RectView(isRed: $appState.isRed))
                    NavigationLink("Link with binding to state variable", destination: RectView(isRed: $childViewIsRed))
                }
            }
            .frame(height: 300)

            RectView(isRed: $appState.isRed)
            RectView(isRed: $childViewIsRed)
        }
    }
}

下面的gif/video是我演示的四件事,从下到上点击这些视图:

我搜索了现有问题。我知道 NavigationView 周围有一些() but that doesn't explain why one type of binding would work fine inside a NavigationView and another wouldn't. Similarly, there are ones around animating changes to @ObservedObjects (@StateObject 会相似吗?)但我不明白为什么对这种绑定进行动画更改会在a NavigatonView 而不是在里面。

如果相关,我在 macOS 12.2.1 上使用 Xcode 13.2.1,运行,而在 16 英寸 M1 Max MacBook 上又 运行临。 gif/video 中显示的模拟器是 iPhone 11 Pro Max。如果我将这个微型测试应用程序部署到物理 iPhone 7 运行 iOS 15.3.1.

,我会得到相同的结果

老实说,我不确定为什么,但是在 RectView 上使用动画修改器可以毫无问题地出现动画。

struct RectView: View {
@Binding var isRed: Bool

    var body: some View {
        Rectangle()
            .fill(isRed ? Color.red : Color.gray)
            .frame(width: 75, height: 75, alignment: .center)
            .animation(.easeOut(duration: 1), value: isRed)
            .onTapGesture { isRed.toggle() }
    }
}

screen recording example