绑定到 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是我演示的四件事,从下到上点击这些视图:
- 首先,我点击最底部的矩形 - 绑定到
@State
属性 的矩形。它按预期切换动画。我再次点击以使其保持灰色。
- 然后我点击底部的第二个矩形 - 一个绑定到
@StateObject
中的 @Published
属性。一切顺利。
- 接下来,我点击
NavigationLink
,它指向一个绑定到本地 @State
属性 的矩形。当我点击矩形时,过渡效果很好。最底部的矩形也有动画,这是有道理的,因为它们绑定到相同的 属性.
- 最后我点击顶部
NavigationLink
,这导致一个矩形绑定到 @StateObject
中的 @Published
属性。但是当我点击这个矩形时,没有动画。矩形捕捉到红色。它下面的矩形(绑定到相同的 属性)动画效果很好,证明 属性 确实被切换了。但是NavigationView
里面没有动画。为什么?我错过了什么?
我搜索了现有问题。我知道 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 @ObservedObject
s (,@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
关于 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是我演示的四件事,从下到上点击这些视图:
- 首先,我点击最底部的矩形 - 绑定到
@State
属性 的矩形。它按预期切换动画。我再次点击以使其保持灰色。 - 然后我点击底部的第二个矩形 - 一个绑定到
@StateObject
中的@Published
属性。一切顺利。 - 接下来,我点击
NavigationLink
,它指向一个绑定到本地@State
属性 的矩形。当我点击矩形时,过渡效果很好。最底部的矩形也有动画,这是有道理的,因为它们绑定到相同的 属性. - 最后我点击顶部
NavigationLink
,这导致一个矩形绑定到@StateObject
中的@Published
属性。但是当我点击这个矩形时,没有动画。矩形捕捉到红色。它下面的矩形(绑定到相同的 属性)动画效果很好,证明 属性 确实被切换了。但是NavigationView
里面没有动画。为什么?我错过了什么?
我搜索了现有问题。我知道 NavigationView
周围有一些(NavigationView
and another wouldn't. Similarly, there are ones around animating changes to @ObservedObject
s (@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