compose-animations について
Compose 開発者向けに、動きの要件とライフサイクルに応じたアニメーション API の選択を支援するスキルです。コンテンツの識別、テスト、フレーム単位の性能上の注意点も扱います。
主な機能
- 01要件に応じた Compose API の選択
- 02状態アニメーションとジェスチャーの区別
- 03ライフサイクルとコンテンツ識別の確認
- 04性能とテスト上の注意点
活用シーン
- 01UI の表示・非表示アニメーションの選択
- 02共通状態に基づく値の連携
- 03AnimatedContent の切り替えのレビュー
- 04フレーム単位のレイアウトや描画負荷の診断
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ chrisbanes/ skills --skill compose-animationsインストール後、Claude Code で/compose-animationsを入力して読み込まれたか確認します。
同梱ファイルreferences/animated-content.md
詳細
Compose:アニメーション
基本原則
動きとそのライフサイクルを表現できる、最もシンプルな API を選びます。
手順
- 目的を特定します。サブツリーの表示・非表示、単一の値のアニメーション、1 つの状態に基づく複数の値の連動、コンテンツのサイズ変更、コンテンツの切り替え、またはユーザー操作に応じた動きの処理です。
- 表から該当する API を選びます。ターゲット状態 API を優先し、ジェスチャー、中断、または命令的な制御が必要な場合に限り
Animatableを使います。 - ライフサイクルを確認します。アルファアニメーションではコンテンツはコンポジションに残りますが、
AnimatedVisibilityでは終了後に取り除かれます。アンマウントが必要な場合はフェードを使わないでください。 AnimatedContentでは、コンテンツラムダのターゲットから描画し、視覚的な同一性がペイロードの等価性と異なる場合に限りcontentKeyを選びます。異なるアイテム間を切り替える場合は、ターゲット値を同一性として維持する(デフォルト)か、安定したアイテム ID をキーにします。異なるアイテムを共通の表示状態キーや分岐キーにまとめないでください。レビューでは、外側のターゲット状態をキャプチャする描画式を明示し、その箇所ではラムダのターゲットを使うよう推奨します。テストで遷移の同一性を証明する必要がある場合は、遷移中に終了側と開始側のコンテンツを確認します。遷移完了後の表示先だけを確認すると、同一性が共有されている不具合を見逃します。状態保持の詳細については、AnimatedContent の同一性を参照してください。- アニメーション対象の
Stateがフレームごとに変化する場合は、レイアウトまたは描画ブロックの修飾子で使用します。詳細な診断はCompose のパフォーマンスを参照してください。 - この機能が制御する遷移先の切り替えには Navigation Compose の遷移を使い、アートベースの動きには専用ライブラリを使います。
- API、ライフサイクル、コンテンツの同一性が UI に合致し、よりシンプルな API がなく、関連する動作も検証されたら完了です。
API の選択
| 必要なもの | 推奨 |
|---|---|
| 表示・非表示の開始・終了動作を伴うサブツリーの表示・非表示 | AnimatedVisibility |
| 状態に追従する単一の値 | animate*AsState |
| 1 つのブール値、列挙型、または sealed 状態に追従する複数の値 | rememberTransition と子アニメーション |
| 子要素のサイズ変更 | Modifier.animateContentSize() |
| 異なるコンポーザブルツリーで 1 つの領域を埋める | AnimatedContent、または単純なケースでは Crossfade |
| ドラッグ、フリング、中断、または命令的な制御 | Animatable |
デフォルトの動きが適切でない場合は AnimationSpec を使います。複数のアニメーションをツールで識別できるようにするには、個別の label を設定します。
val width by animateDpAsState(
targetValue = if (expanded) 200.dp else 56.dp,
animationSpec = spring(dampingRatio = 0.7f),
label = "fabWidth",
)
同期を保つ必要がある値には、独立した複数の animate*AsState 呼び出しではなく、1 つの遷移に定義します。
val transition = rememberTransition(targetState = phase, label = "phase")
val alpha by transition.animateFloat(label = "alpha") { target ->
if (target == Phase.Visible) 1f else 0f
}
val offset by transition.animateDp(label = "offset") { target ->
if (target == Phase.Visible) 0.dp else 24.dp
}
アニメーション付きの塗りつぶしでは、色が毎フレーム更新される場合、値を受け取る形式の background よりも drawBehind { drawRect(color.value) } を優先します。API の選択に迷った場合は、公式のアニメーション API の選び方ガイドを参照してください。繰り返しサイクルには rememberInfiniteTransition を、シーク可能な進行状況やテストで制御する進行状況には SeekableTransitionState を使います。
このスキルを使わない場合
- 副作用のタイミングやクリックを起点とする処理には、Compose の状態と副作用を使います。
- 状態読み取りや再コンポジションの詳細な診断には、Compose のパフォーマンスを使います。
コメント
Markdown 対応