4

次の簡単な例を考えてみましょう。

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()
            }
            
    }
}

結果の円をタップすると、次のアニメーションが生成されます。

ここに画像の説明を入力

ネストされた円は、独自のタイミング関数 (スプリング) で新しいグローバル位置にアニメーション化されますが、外側の円/親ビューは、easeInOut タイミング関数で新しいグローバル位置にアニメーション化されます。理想的には、修飾子が親ビューの抽象化レベルで機能する場合、すべての子が親のタイミング関数でアニメーション化されます (この場合はoffsetだけでなく、 のようなものもありますposition)。

これはおそらく、SwiftUI レンダリング エンジンがレイアウト パスのビュー階層で影響を受けるすべての子の新しいグローバル プロパティを計算し、アタッチされた最も具体的なアニメーション修飾子に基づいて各プロパティへの変更をアニメーション化するために発生します (この場合、相対位置親内の子の値は変更されません)。これにより、そのビューのサブビューが独自の複雑なアニメーションを実行している可能性がある場合に、ビューを適切に変換するような単純なことを行うのが非常に困難になります (親ビューはそれを認識しておらず、実際に認識すべきではありません)。

私が気付いたもう 1 つの癖は、この特定の例では、offset モディファイアに直接アタッチされたままであるにもかかわらず、offset モディファイアのanimation(nil)直前にモディファイア追加すると、外側の円のアニメーションが壊れることです。.easeInOutこれは、これらの修飾子がどのように連鎖されているかについての私の理解に違反しています。(このソースによると) アニメーション修飾子は、次のネストされたアニメーション修飾子まで、それに伴うすべてのビューに適用されます。

4

2 に答える 2