SwiftUI:NavigationView 内的动画
SwiftUI: Animation Inside NavigationView
我正在尝试在 SwiftUI 中创建一个简单的动画。它基本上是一个改变其框架的矩形,同时保持在父视图的中心。
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Text("Text")
ZStack {
Color.blue
SquareAnimation().frame(width: 200, height: 200, alignment: .center)
}
Text("Text")
}
}
}
}
struct SquareAnimation: View {
var currentRect = CGRect(x: 0, y: 0, width: 50, height: 50)
var finalRect = CGRect(x: 0, y: 0, width: 100, height: 100)
private let animation = Animation.easeInOut(duration: 1).repeatForever(autoreverses: true)
@State var animate = false
var body: some View {
ZStack() {
Color.clear
Rectangle()
.frame(width: animate ? finalRect.width: currentRect.width, height: animate ? finalRect.height: currentRect.height, alignment: .center)
.animation(animation, value: animate)
.onAppear() {
animate = true
}
}
}
}
问题是,如果使用 NavigationView
,黑色矩形不会停留在中心。
我也使用了显式动画但无济于事。为什么 NavigationView
会影响矩形动画?
谢谢!
当 NavigationView 中的视图框架为零时,会过早调用 onAppear,因此应用动画以从零变为值。
这是有效的解决方法。使用 Xcode 12.4 / iOS 14.4
测试
var body: some View {
ZStack() {
Color.clear
Rectangle()
.frame(width: animate ? finalRect.width: currentRect.width, height: animate ? finalRect.height: currentRect.height, alignment: .center)
.animation(animation, value: animate)
.onAppear {
DispatchQueue.main.async {
// << postpone till end of views construction !!
animate = true
}
}
}
}
注意:几乎所有 为什么 问题只能由 Apple 回答...可能是错误,也可能是实现细节。
根据我的经验,这似乎是一个普遍问题。这是一个适用于我的通用解决方案 – 我知道这很简单,但我不喜欢必要的代码,因此希望尽量减少重复。
struct NavigationViewInitialLayoutWorkaround: ViewModifier {
@Binding var canAnimate: Bool
func body(content: Content) -> some View {
content.onAppear {
if !canAnimate {
DispatchQueue.main.async {
canAnimate = true
}
}
}
}
}
将此修饰符应用于动画受 NavigationView 祖先的初始布局问题影响的任何视图。
@State private var canAnimate: Bool = false
NavigationView {
AllMyAnimatableViews()
.animation(canAnimate ? .default : .none)
}
.modifier(NavigationViewInitialLayoutWorkaround(canAnimate: $canAnimate))
我正在尝试在 SwiftUI 中创建一个简单的动画。它基本上是一个改变其框架的矩形,同时保持在父视图的中心。
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Text("Text")
ZStack {
Color.blue
SquareAnimation().frame(width: 200, height: 200, alignment: .center)
}
Text("Text")
}
}
}
}
struct SquareAnimation: View {
var currentRect = CGRect(x: 0, y: 0, width: 50, height: 50)
var finalRect = CGRect(x: 0, y: 0, width: 100, height: 100)
private let animation = Animation.easeInOut(duration: 1).repeatForever(autoreverses: true)
@State var animate = false
var body: some View {
ZStack() {
Color.clear
Rectangle()
.frame(width: animate ? finalRect.width: currentRect.width, height: animate ? finalRect.height: currentRect.height, alignment: .center)
.animation(animation, value: animate)
.onAppear() {
animate = true
}
}
}
}
问题是,如果使用 NavigationView
,黑色矩形不会停留在中心。
我也使用了显式动画但无济于事。为什么 NavigationView
会影响矩形动画?
谢谢!
当 NavigationView 中的视图框架为零时,会过早调用 onAppear,因此应用动画以从零变为值。
这是有效的解决方法。使用 Xcode 12.4 / iOS 14.4
测试var body: some View {
ZStack() {
Color.clear
Rectangle()
.frame(width: animate ? finalRect.width: currentRect.width, height: animate ? finalRect.height: currentRect.height, alignment: .center)
.animation(animation, value: animate)
.onAppear {
DispatchQueue.main.async {
// << postpone till end of views construction !!
animate = true
}
}
}
}
注意:几乎所有 为什么 问题只能由 Apple 回答...可能是错误,也可能是实现细节。
根据我的经验,这似乎是一个普遍问题。这是一个适用于我的通用解决方案 – 我知道这很简单,但我不喜欢必要的代码,因此希望尽量减少重复。
struct NavigationViewInitialLayoutWorkaround: ViewModifier {
@Binding var canAnimate: Bool
func body(content: Content) -> some View {
content.onAppear {
if !canAnimate {
DispatchQueue.main.async {
canAnimate = true
}
}
}
}
}
将此修饰符应用于动画受 NavigationView 祖先的初始布局问题影响的任何视图。
@State private var canAnimate: Bool = false
NavigationView {
AllMyAnimatableViews()
.animation(canAnimate ? .default : .none)
}
.modifier(NavigationViewInitialLayoutWorkaround(canAnimate: $canAnimate))