考虑这个简单的例子:
struct TestView: View {
@State private var enabled = false
var body: some View {
Circle()
.foregroundColor(.red)
.overlay(
Circle()
.foregroundColor(.blue)
.frame(width: 50, height: 50)
.animation(.spring())
)
.frame(width: 100, height: 100)
.offset(x: 0, y: enabled ? -50 : 50)
.animation(.easeIn(duration: 1.0))
.onTapGesture{
enabled.toggle()
}
}
}
当点击生成的圆圈时,这会产生以下动画:嵌套的圆用它自己的计时函数( Spring )动画到它的新全局位置,而外圆/父 View 用它的easieInOut 计时函数动画到新的全局位置。理想情况下,如果修饰符在父 View 抽象级别工作(在本例中为
offset
,但也有类似 position
之类的东西),则所有子项都将使用父项计时函数进行动画处理。据推测,发生这种情况是因为 SwiftUI 渲染引擎在布局传递中为 View 层次结构中所有受影响的子项计算新的全局属性,并根据附加的最具体的动画修改器对每个属性的更改进行动画处理(即使在这种情况下,相对位置父级中的子级不会改变)。这使得在 View 的 subview 可能有自己复杂的动画运行时(父 View 不知道也不应该知道),做一些像正确翻译 View 这样简单的事情变得非常困难。
我注意到的另一个怪癖是,在这个特定的例子中,添加一个
animation(nil)
尽管 .easeInOut
,在偏移修饰符之前的修饰符会中断外圆上的动画。保留直接附加到偏移修改器。这违反了我对这些修改器如何链接的理解,其中(根据 this source )动画修改器适用于它需要的所有 View ,直到下一个嵌套的动画修改器。
最佳答案
这对我来说似乎是一个错误,可能值得向 Apple 报告。我确实找到了一个奇怪的解决方法,通过在 .offset 修饰符之前添加另一个修饰符:
struct TestView: View {
@State private var enabled = false
var body: some View {
Circle()
.foregroundColor(.red)
.overlay(
Circle()
.foregroundColor(.blue)
.frame(width: 50, height: 50)
.animation(.spring())
)
.frame(width: 100, height: 100)
.scaleEffect(1) // <------- this doesn't do anything but somehow overrides the animation
.offset(x: 0, y: enabled ? -50 : 50)
.animation(.easeIn(duration: 1.0))
.onTapGesture{
enabled.toggle()
}
}
}
我已经尝试过使用 scaleEffect、rotationEffect 和 rotation3DEffect,它们都有效。并非所有修饰符都有效。我真的很好奇为什么这些特定的会这样做。.animation(nil) 对我来说似乎也是一个错误。
关于ios - SwiftUI - 如何覆盖嵌套的偏移/位置动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65544581/