[英]SwiftUI unexpected animations when toggling animations In .onAppear (using a GeometryReader's size)
我在 SwiftUI 中有一个奇怪的SwiftUI
行为。 我试图创建一个在下面演示它的最小视图。
我想用淡入淡出和缩放效果在三个圆圈中制作动画(请参阅下面的“我期望什么”栏)。 但是,圆圈的大小取决于视图的宽度,所以我使用GeometryReader
来获得它。
我想在.onAppear(perform:)
中启动 animation ,但在调用时, GeometryReader
尚未设置size
属性。 我最终得到的是您在"Unwanted Animation 1"中看到的 animation。 这是由于帧从.zero
动画到正确的大小。
但是,每当我尝试通过添加.animation(nil, value: size)
修饰符来禁用帧的动画时,我都会得到一个非常奇怪的 animation 行为(请参阅“不需要的 Animation 2” )。 这个我完全不明白。 它以某种方式为 animation 添加了水平平移,使其看起来更糟。 任何想法这里发生了什么以及如何解决这个问题?
奇怪的是,如果我像这样使用明确的 animation ,一切正常:
.onAppear {
withAnimation {
show.toggle()
}
}
但我想了解这里发生了什么。
谢谢!
import SwiftUI
struct TestView: View {
@State private var show = false
@State private var size: CGSize = .zero
var body: some View {
VStack {
circle
circle
circle
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.contentShape(Rectangle())
.background {
GeometryReader { proxy in
Color.clear.onAppear { size = proxy.size }
}
}
.onAppear { show.toggle() }
}
private var circle: some View {
Circle()
.frame(width: circleSize, height: circleSize)
.animation(nil, value: size) // This make the circles animate in from the side for some reason (see "Strange Animation 2")
.opacity(show ? 1 : 0)
.scaleEffect(show ? 1 : 2)
.animation(.easeInOut(duration: 1), value: show)
}
private var circleSize: Double {
size.width * 0.2 // Everything works fine if this is a constant
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
实际大小在第一次布局后已知,但.onAppear
在之前调用,因此布局(包括可动画的帧更改)位于 animation 之下。
为了解决这个问题,我们需要延迟 state 改变一点(直到第一个布局/渲染完成),比如
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
show.toggle()
}
}
...这就是为什么withAnimation
也有效的原因——它实际上将关闭调用延迟到下一个周期。
用 Xcode 13 / iOS 15 测试
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.