ハイライト
SwiftUI では、iOS 17 に 2 つの新しい API が導入されています。
phaseAnimatorマルチステージループ/イベントドリブンアニメーションを定義するには、keyframeAnimatorマルチトラック キーフレーム アニメーションの作成に使用例され、どちらも各段階でアニメーション カーブのカスタマイズをサポートし、複雑なアニメーションの実装を「手書きのステート マシン」から「宣言的構成」に変更できるようにします。
主な内容
従来のアニメーションの限界
SwiftUI チームの Tim 氏は次のように指摘しています。withAnimation「古い状態から新しい状態へ」の遷移のみを処理できます。多くのアニメーション要件はより複雑です。読み込みインジケーターは継続的にループする必要があり、ボタンはパルス効果を再生し、クリック後に再開する必要があります。これらのアニメーションには複数のステップがあり、これらのステップは単純な状態切り替えではありません。
Phase Animator: マルチステージアニメーション
(03:13)phaseAnimatorモディファイアは一連のフェーズを受け入れ、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:48)keyframeAnimatorアニメーション プロパティごとに個別のトラックを定義でき、それぞれに独自のキーフレームのセットが含まれます。
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:26)KeyframeTimelineビューに依存せずに独立して使用例できます。
let myKeyframes = KeyframeTimeline(initialValue: CGPoint.zero) {
KeyframeTrack(\.x) { ... }
KeyframeTrack(\.y) { ... }
}
let duration: TimeInterval = myKeyframes.duration
let value = myKeyframes.value(time: 1.2)
キーポイント:
- アニメーションの合計時間をクエリできます。
- いつでも値をクエリできます
- カスタム アニメーション ロジックまたは他のシステムとの統合に適しています
##詳細
フェーズアニメーターの仕組み
(03:57) フェーズ アニメーターのワークフロー:
- 最初のフェーズは、ビューが最初に表示されたときにアクティブになります。
- SwiftUI はすぐに次のステージへのアニメーション遷移を開始します
- アニメーションが完了すると、自動的に次のステージに進みます。
- 最後のステージに到達したら、最初のステージにループバックします。
提供されている場合triggerパラメーター、トリガー値が変化するとアニメーションはすべてのステージを 1 回再生し、その後停止します。
キーフレームタイプの詳細な説明
3 つのキーフレーム タイプにはそれぞれ、適用可能なシナリオがあります。
- LinearKeyframe: 一定の速度で変化します。一定の速度が必要な属性に適しています。
- CubicKeyframe: 滑らかな曲線、ほとんどの視覚的プロパティに適しています
- SpringKeyframe: 物理的なスプリング効果。弾性が必要なプロパティに適しています。
SpringKeyframeターゲット値とスプリング パラメーターを指定するだけで、SwiftUI が自動的に継続時間を計算できます。
重要なポイント
-
ループリマインダーアニメーション
- 何をすべきか: To Do アイテムと通知リマインダーに呼吸ライト効果を追加します
- なぜそれを行う価値があるのか:
phaseAnimator数行のコードでループ アニメーションを作成し、タイマーやステート マシンは必要ありません - 開始方法: 2 つのステージ (通常/ハイライト) の配列を定義します。
.phaseAnimatorリマインダービューを変更します。animationクロージャで指定されている.easeInOut(duration: 1.5)
-
アニメーションをいいね!/収集
- 機能: ユーザーが気に入ったときに、多段階のハート形のズーム アニメーションを再生します。
- なぜそれを行う価値があるのか:
triggerパターンを使用例するとイベント駆動のアニメーションがシンプルになり、スケーリング、回転、色の変更を組み合わせることができます。 - 始め方: 定義
initial->scaleUp->settle3 段階で使用例trigger: likeCountトリガー、各ステージは異なるスプリングパラメータを指定します
-
マップルートローミング
- 操作方法: 地図上にランニング/サイクリングのルートを表示し、そのルートに沿ってカメラを飛行させます。
- なぜそれを行う価値があるのか:
mapCameraKeyframeAnimation複雑なカメラコントロールを宣言型構成に変える - 開始方法: ルートの座標点配列を次のように準備します。
centerCoordinateトラック作成キーフレーム (各ポイントに 1 つ)CubicKeyframe
-
読み込みステータスインジケータ
- やるべきこと: システムよりも読み込みアニメーションをカスタマイズします
ProgressViewさらに詳しいブランドの特徴 - なぜそれを行う価値があるのか:
KeyframeTimeline単独で使用例することも、組み合わせて使用例することもできますCanvas任意の形状のアニメーションを描画する - 開始方法: 作成する
KeyframeTimeline時間の経過に伴う形状プロパティの変化を定義するには、次を使用例します。TimelineViewドライバーの再描画
- やるべきこと: システムよりも読み込みアニメーションをカスタマイズします
-
複雑な遷移アニメーション
- 内容: ビューの表示/非表示時に複数プロパティの組み合わせアニメーションを再生します。
- 実行する価値がある理由: キーフレーム アニメーションを使用例すると、複数の属性 (位置、スケーリング、回転、透明度) を個別に制御し、調整できます。
- 開始方法: すべてのアニメーション プロパティを含む構造を定義し、
KeyframeTrack、ビュー修飾子に適用されます.keyframeAnimator
関連セッション
- SwiftUI アニメーションを探索する — SwiftUI アニメーションの基本原則
- スプリングを使ってアニメーションする — スプリングアニメーションを徹底解説
- SwiftUI の要点 — SwiftUI の基本概念
- スクロール ビューを超えて — ScrollView のスクロール遷移アニメーション
コメント
GitHub Issues · utterances