WWDC Quick Look 💓 By SwiftGGTeam
Wind your way through advanced animations in SwiftUI

Wind your way through advanced animations in SwiftUI

元の動画を見る

ハイライト

SwiftUI では、iOS 17 に 2 つの新しい API が導入されています。phaseAnimatorマルチステージループ/イベントドリブンアニメーションを定義するには、keyframeAnimatorマルチトラック キーフレーム アニメーションの作成に使用例され、どちらも各段階でアニメーション カーブのカスタマイズをサポートし、複雑なアニメーションの実装を「手書きのステート マシン」から「宣言的構成」に変更できるようにします。

主な内容

従来のアニメーションの限界

SwiftUI チームの Tim 氏は次のように指摘しています。withAnimation「古い状態から新しい状態へ」の遷移のみを処理できます。多くのアニメーション要件はより複雑です。読み込みインジケーターは継続的にループする必要があり、ボタンはパルス効果を再生し、クリック後に再開する必要があります。これらのアニメーションには複数のステップがあり、これらのステップは単純な状態切り替えではありません。

Phase Animator: マルチステージアニメーション

03:13phaseAnimatorモディファイアは一連のフェーズを受け入れ、SwiftUI はそれらの間を自動的に循環します。

最も単純な例は、ハイライトと通常の 2 フェーズ ループです。

OverdueReminderView()
    .phaseAnimator([false, true]) { content, value in
        content
            .foregroundStyle(value ? .red : .primary)
    } animation: { _ in
        .easeInOut(duration: 1.0)
    }

キーポイント:

  • ステージ配列を提供し、SwiftUI が自動的にループします
  • ビューの属性は各段階で変更できます -animationクロージャはターゲット ステージを受け取り、さまざまなステージにさまざまなアニメーションを指定できます。
  • Springはデフォルトで使用例されており、使用例できますanimation閉鎖範囲

(06:20) カスタム列挙型を使用例してより複雑なステージを定義します。

ReactionView()
    .phaseAnimator(
        Phase.allCases,
        trigger: reactionCount
    ) { content, phase in
        content
            .scaleEffect(phase.scale)
            .offset(y: phase.verticalOffset)
    } animation: { phase in
        switch phase {
        case .initial: .smooth
        case .move: .easeInOut(duration: 0.3)
        case .scale: .spring(duration: 0.3, bounce: 0.7)
        }
    }

enum Phase: CaseIterable {
    case initial
    case move
    case scale

    var verticalOffset: Double {
        switch self {
        case .initial: 0
        case .move, .scale: -64
        }
    }

    var scale: Double {
        switch self {
        case .initial: 1.0
        case .move: 1.1
        case .scale: 1.8
        }
    }
}

キーポイント:

  • カスタム列挙型が続きますCaseIterable、それぞれのケースでこのステージの属性値を定義します -triggerパラメータにより、イベントがトリガーされたときにアニメーションが (ループではなく) 1 回再生されます。
  • 各ステージは独自のアニメーション カーブを持つことができます

Keyframe Animator: キーフレーム アニメーション

09:48keyframeAnimatorアニメーション プロパティごとに個別のトラックを定義でき、それぞれに独自のキーフレームのセットが含まれます。

struct AnimationValues {
    var scale = 1.0
    var verticalStretch = 1.0
    var verticalTranslation = 0.0
    var angle = Angle.zero
}

ReactionView()
    .keyframeAnimator(initialValue: AnimationValues()) { content, value in
        content
            .foregroundStyle(.red)
            .rotationEffect(value.angle)
            .scaleEffect(value.scale)
            .scaleEffect(y: value.verticalStretch)
            .offset(y: value.verticalTranslation)
    } keyframes: { _ in
        KeyframeTrack(\.angle) {
            CubicKeyframe(.zero, duration: 0.58)
            CubicKeyframe(.degrees(16), duration: 0.125)
            CubicKeyframe(.degrees(-16), duration: 0.125)
            CubicKeyframe(.degrees(16), duration: 0.125)
            CubicKeyframe(.zero, duration: 0.125)
        }

        KeyframeTrack(\.verticalStretch) {
            CubicKeyframe(1.0, duration: 0.1)
            CubicKeyframe(0.6, duration: 0.15)
            CubicKeyframe(1.5, duration: 0.1)
            CubicKeyframe(1.05, duration: 0.15)
            CubicKeyframe(1.0, duration: 0.88)
            CubicKeyframe(0.8, duration: 0.1)
            CubicKeyframe(1.04, duration: 0.4)
            CubicKeyframe(1.0, duration: 0.22)
        }

        KeyframeTrack(\.scale) {
            LinearKeyframe(1.0, duration: 0.36)
            SpringKeyframe(1.5, duration: 0.8, spring: .bouncy)
            SpringKeyframe(1.0, spring: .bouncy)
        }

        KeyframeTrack(\.verticalTranslation) {
            LinearKeyframe(0.0, duration: 0.1)
            SpringKeyframe(20.0, duration: 0.15, spring: .bouncy)
            SpringKeyframe(-60.0, duration: 1.0, spring: .bouncy)
            SpringKeyframe(0.0, spring: .bouncy)
        }
    }

キーポイント:

  • initialValueアニメーション開始時の初期値を定義します
  • それぞれKeyframeTrack属性に対応するアニメーショントラック
  • キーフレームの種類:LinearKeyframe(線形補間)、CubicKeyframe(3次曲線)、SpringKeyframe(春アニメ)
  • トラックごとに異なる長さとキーフレーム数を設定できます
  • トラックをインターレースして、豊かな組み合わせ効果を生み出すことができます

マップキーフレームアニメーション

(15:22)キーフレームアニメーションも使用例可能Mapカメラ:

Map(initialPosition: .rect(route.rect)) {
    MapPolyline(coordinates: route.coordinates)
        .stroke(.orange, lineWidth: 4.0)
    Marker("Start", coordinate: route.start)
        .tint(.green)
    Marker("End", coordinate: route.end)
        .tint(.red)
}
.mapCameraKeyframeAnimation(trigger: playTrigger) { initialCamera in
    KeyframeTrack(\.centerCoordinate) {
        let points = route.points
        for point in points {
            CubicKeyframe(point.coordinate, duration: 16.0 / Double(points.count))
        }
        CubicKeyframe(initialCamera.centerCoordinate, duration: 4.0)
    }
    KeyframeTrack(\.heading) {
        CubicKeyframe(heading(from: route.start.coordinate, to: route.end.coordinate), duration: 6.0)
        CubicKeyframe(heading(from: route.end.coordinate, to: route.end.coordinate), duration: 8.0)
        CubicKeyframe(initialCamera.heading, duration: 6.0)
    }
    KeyframeTrack(\.distance) {
        CubicKeyframe(24000, duration: 4)
        CubicKeyframe(18000, duration: 12)
        CubicKeyframe(initialCamera.distance, duration: 4)
    }
}

キーポイント:

  • mapCameraKeyframeAnimationマップ固有のキーフレーム アニメーション モディファイアです
  • カメラの中心座標、方位、距離を制御できます
  • カメラはルートに沿ってスムーズに飛行し、最終的には初期位置に戻ります

KeyframeTimeline

16:26KeyframeTimelineビューに依存せずに独立して使用例できます。

let myKeyframes = KeyframeTimeline(initialValue: CGPoint.zero) {
    KeyframeTrack(\.x) { ... }
    KeyframeTrack(\.y) { ... }
}

let duration: TimeInterval = myKeyframes.duration
let value = myKeyframes.value(time: 1.2)

キーポイント:

  • アニメーションの合計時間をクエリできます。
  • いつでも値をクエリできます
  • カスタム アニメーション ロジックまたは他のシステムとの統合に適しています

##詳細

フェーズアニメーターの仕組み

(03:57) フェーズ アニメーターのワークフロー:

  1. 最初のフェーズは、ビューが最初に表示されたときにアクティブになります。
  2. SwiftUI はすぐに次のステージへのアニメーション遷移を開始します
  3. アニメーションが完了すると、自動的に次のステージに進みます。
  4. 最後のステージに到達したら、最初のステージにループバックします。

提供されている場合triggerパラメーター、トリガー値が変化するとアニメーションはすべてのステージを 1 回再生し、その後停止します。

キーフレームタイプの詳細な説明

3 つのキーフレーム タイプにはそれぞれ、適用可能なシナリオがあります。

  • LinearKeyframe: 一定の速度で変化します。一定の速度が必要な属性に適しています。
  • CubicKeyframe: 滑らかな曲線、ほとんどの視覚的プロパティに適しています
  • SpringKeyframe: 物理的なスプリング効果。弾性が必要なプロパティに適しています。

SpringKeyframeターゲット値とスプリング パラメーターを指定するだけで、SwiftUI が自動的に継続時間を計算できます。

重要なポイント

  1. ループリマインダーアニメーション

    • 何をすべきか: To Do アイテムと通知リマインダーに呼吸ライト効果を追加します
    • なぜそれを行う価値があるのか:phaseAnimator数行のコードでループ アニメーションを作成し、タイマーやステート マシンは必要ありません
    • 開始方法: 2 つのステージ (通常/ハイライト) の配列を定義します。.phaseAnimatorリマインダービューを変更します。animationクロージャで指定されている.easeInOut(duration: 1.5)
  2. アニメーションをいいね!/収集

    • 機能: ユーザーが気に入ったときに、多段階のハート形のズーム アニメーションを再生します。
    • なぜそれを行う価値があるのか:triggerパターンを使用例するとイベント駆動のアニメーションがシンプルになり、スケーリング、回転、色の変更を組み合わせることができます。
    • 始め方: 定義initial -> scaleUp -> settle3 段階で使用例trigger: likeCountトリガー、各ステージは異なるスプリングパラメータを指定します
  3. マップルートローミング

    • 操作方法: 地図上にランニング/サイクリングのルートを表示し、そのルートに沿ってカメラを飛行させます。
    • なぜそれを行う価値があるのか:mapCameraKeyframeAnimation複雑なカメラコントロールを宣言型構成に変える
    • 開始方法: ルートの座標点配列を次のように準備します。centerCoordinateトラック作成キーフレーム (各ポイントに 1 つ)CubicKeyframe
  4. 読み込みステータスインジケータ

    • やるべきこと: システムよりも読み込みアニメーションをカスタマイズしますProgressViewさらに詳しいブランドの特徴
    • なぜそれを行う価値があるのか:KeyframeTimeline単独で使用例することも、組み合わせて使用例​​することもできますCanvas任意の形状のアニメーションを描画する
    • 開始方法: 作成するKeyframeTimeline時間の経過に伴う形状プロパティの変化を定義するには、次を使用例します。TimelineViewドライバーの再描画
  5. 複雑な遷移アニメーション

    • 内容: ビューの表示/非表示時に複数プロパティの組み合わせアニメーションを再生します。
    • 実行する価値がある理由: キーフレーム アニメーションを使用例すると、複数の属性 (位置、スケーリング、回転、透明度) を個別に制御し、調整できます。
    • 開始方法: すべてのアニメーション プロパティを含む構造を定義し、KeyframeTrack、ビュー修飾子に適用されます.keyframeAnimator

関連セッション

コメント

GitHub Issues · utterances