雑学1473946 views
小学理科720872 views
英語615652 views
MathPython499435 views
いろは3019021 views
高校国語789226 views
中学理科1632333 views
小学算数1202296 views
LaTeX963955 views
小学社会311093 views
Help
Tools

English

SwiftUI animation モディファイアと暗黙的アニメーション

SwiftUI には .animation モディファイアを使った暗黙的アニメーションという仕組みがある。withAnimation が「このタイミングで」と明示するのに対し、暗黙的アニメーションは「この値が変わったら常に」という宣言的なアプローチだ。

animation モディファイアの基本

.animation モディファイアは、特定の値の変化を監視し、その値に依存するビューの変更をアニメーション化する。

struct ContentView: View {
    @State private var isExpanded = false
    
    var body: some View {
        VStack {
            Rectangle()
                .fill(.blue)
                .frame(width: isExpanded ? 200 : 100,
                       height: isExpanded ? 200 : 100)
                .animation(.easeInOut, value: isExpanded)
            
            Button("Toggle") {
                isExpanded.toggle()
            }
        }
    }
}

withAnimation で囲まなくても、isExpanded が変わるたびに自動でアニメーションが実行される。

value パラメータの重要性

iOS 15 以降、.animation には必ず value パラメータを指定する必要がある。これは「どの値の変化に反応するか」を明示するためだ。

// iOS 15 以降の正しい書き方
.animation(.spring(), value: someValue)

// 非推奨(iOS 15 で deprecated)
.animation(.spring())

value を省略した古い書き方は、意図しないアニメーションが発生する原因になっていた。どの状態変化に対してアニメーションするかを明確にすることで、予測可能な動作が保証される。

複数の値を監視

複数の値の変化に対してアニメーションさせたい場合は、animation モディファイアを複数つけるか、値をまとめる。

struct MultiValueView: View {
    @State private var offset: CGFloat = 0
    @State private var rotation: Double = 0
    
    var body: some View {
        Rectangle()
            .frame(width: 100, height: 100)
            .offset(y: offset)
            .rotationEffect(.degrees(rotation))
            .animation(.spring(), value: offset)
            .animation(.easeInOut, value: rotation)
    }
}

offset の変化にはスプリング、rotation の変化には easeInOut と、別々のアニメーションを適用できる。

暗黙的 vs 明示的アニメーション

暗黙的アニメーション(.animation)

ビューの定義時にアニメーションを宣言。値が変われば常にアニメーション。宣言的で SwiftUI らしいアプローチ。

明示的アニメーション(withAnimation)

状態変更時にアニメーションを指定。特定のアクションだけアニメーションさせたい場合に有効。手続き的なアプローチ。

どちらを使うかは設計思想による。「このビューは常にアニメーションする」なら暗黙的、「このボタンを押したときだけ」なら明示的が適している。

animation(nil) でアニメーションを無効化

特定の変更だけアニメーションさせたくない場合、.animation(nil, value:) を使う。

struct SelectiveAnimationView: View {
    @State private var position: CGFloat = 0
    @State private var color: Color = .blue
    
    var body: some View {
        Rectangle()
            .fill(color)
            .frame(width: 100, height: 100)
            .offset(x: position)
            .animation(.spring(), value: position)
            .animation(nil, value: color)  // 色の変化はアニメーションしない
    }
}

これにより、位置の変化はアニメーションするが、色の変化は即座に反映される。

適用順序の注意点

animation モディファイアは、それより上に書かれたモディファイアにのみ影響する。

Rectangle()
    .fill(color)
    .animation(.easeInOut, value: color)  // fill に影響
    .frame(width: size, height: size)
    .animation(.spring(), value: size)     // frame に影響

モディファイアチェーンの順序を意識することで、部分的なアニメーション制御が可能になる。このあたりは SwiftUI のモディファイア適用順序の理解が前提となる。