SwiftUI - 如何覆盖嵌套的偏移/位置动画?

roo*_*ubu 6 ios swift swiftui swiftui-animation

考虑这个简单的例子:

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()
            }
            
    }
}
Run Code Online (Sandbox Code Playgroud)

点击生成的圆圈时,会产生以下动画:

在此输入图像描述

嵌套圆通过其自己的计时函数 (spring) 动画到新的全局位置,而外圆/父视图通过其 escapeInOut 计时函数动画到新的全局位置。理想情况下,如果修改器在父视图抽象级别上工作(在本例中为 ,offset但也包括类似 的东西position),则所有子项都将使用父项计时函数进行动画处理。

发生这种情况大概是因为 SwiftUI 渲染引擎在布局过程中为视图层次结构中所有受影响的子项计算新的全局属性,并根据附加的最具体的动画修改器对每个属性进行动画更改(即使在本例中,相对位置父级中的子级不会改变)。当该视图的子视图可能正在运行自己的复杂动画(父视图不知道也不应该知道)时,这使得执行像正确翻译视图这样简单的事情变得非常困难。

我注意到的另一个怪癖是,在这个特定的示例中,在偏移修改器之前animation(nil)添加一个修改器会破坏外圆上的动画,尽管其余部分直接附加到偏移修改器。这违反了我对这些修改器如何链接的理解,其中(根据此来源)动画修改器适用于它所需要的所有视图,直到下一个嵌套动画修改器。.easeInOut

bze*_*e12 6

这对我来说似乎是一个错误,可能值得向苹果报告。我确实找到了一个奇怪的解决方法,通过在 .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()
            }
            
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经尝试过使用scaleEffect、rotationEffect 和rotation3DEffect,它们都有效。并非所有修饰符都有效。我真的很好奇为什么这些特定的会这样做。

.animation(nil) 的事情对我来说似乎也是一个错误。