jetpack-compose-m3 について
Wear Compose Material3 を使った Wear OS UI の構築と移行を支援するスキルです。バージョンやサンプルの確認、コンポーネントの使い方、Wear 向けレイアウトとナビゲーションの規則を案内します。
主な機能
- 01Wear Compose Material3 の移行ガイド
- 02バージョンと互換性の確認
- 03コンポーネントサンプルの確認
- 04Scaffold とリストレイアウトの指針
- 05Material テーマとデフォルト値
- 06Wear のナビゲーション規則
活用シーン
- 01旧 Wear Compose 画面の移行
- 02Wear Material3 コンポーネントの追加
- 03スクロール可能な Wear OS 画面の構築
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ android/ skills --skill jetpack-compose-m3インストール後、Claude Code で/jetpack-compose-m3を入力して読み込まれたか確認します。
同梱ファイルreferences/android/training/wearables/compose/migrate-to-material3.md
詳細
前提条件と互換性
- Wear OS Compose Material3 のバージョン:
androidx.wear.compose:compose-material3の最新の安定版{VERSION}を特定するための内部ツールが利用できる場合は、そのツールを使用してください。- 利用できない場合は、公式の Maven メタデータ XMLを取得して
{VERSION}を特定してください(-alpha、-beta、-rcを除いたうえで、最も大きい番号を選びます)。
- 利用できない場合は、公式の Maven メタデータ XMLを取得して
- 厳格な遵守: 安定版として記載されているバージョンがある場合、ユーザーから別途指示がない限り、必ずそのバージョンを使用してください。エディターで最初に「Unresolved reference」エラーが発生した場合や、ウェブ検索結果が古い場合でも、バージョンを下げてはいけません。
- Kotlin のバージョン: Wear Compose Material3 では、Kotlin 2.0.0 以上を使用してください。
- Compose コンパイラー:
- Kotlin のバージョンが 2.0.0 以上の場合、プロジェクトでは
org.jetbrains.kotlin.plugin.composeGradle プラグインを使用する必要があります。 - Kotlin のバージョンが 2.0.0 未満の場合、プロジェクトでは
composeOptionsのkotlinCompilerExtensionVersionを使用し、Compose と Kotlin の互換性マップに合わせる必要があります。
- Kotlin のバージョンが 2.0.0 以上の場合、プロジェクトでは
- 最小 SDK:
minSdkが 25(Wear OS 2.0)以上であることを確認してください。 - サンプル抽出の必須要件: Wear Compose ライブラリには、すべてのコンポーネントの個別サンプルを含む追加の JAR ファイルが付属しています。Capability 2 のサンプルをローカルキャッシュに抽出するまでは、コードの変更を提案してはいけません。ライブラリのソースファイルは不完全であり、これらのサンプルの代わりにはなりません。抽出を省略することは、環境設定の不備にあたります。
注意事項
- 同期と検証の必須要件:
libs.versions.tomlまたはbuild.gradle.ktsのバージョンを更新した後は、コードをリファクタリングする前に、必ず Gradle の同期を実行してください。これにより、環境でライブラリが正しく解決されていることを確認できます。 - 推測の禁止(エラープロトコル): 同期の成功後に「Unresolved Reference」または API の不一致が発生した場合、ライブラリのバージョンを下げて「修正」しようとしてはいけません。
機能とツール
機能 1:移行
古いバージョンの Wear OS Compose または Horologist から移行する場合は、このガイダンスを使用してください。
- 開発者から別途指示がない限り、
{VERSION}の Wear Compose Material3 最新安定版を使用してください。 - 移行ガイドを読んでください。
- 移行ガイドに記載されている公式のコンポーネント対応表を使用してください。
- コンポーネント(例:
Chip->Button)をリファクタリングする前に、パラメーター名、スロットの型、「Expressive」デザイントークンを確認してください。 - Horologist の Composable、Compose Layout、Compose Material ライブラリは使用しないでください。
- 必ず機能 3 のコンポーネントに関するガイダンスを確認してください。
- 移行後にスクリーンショットテストが失敗することを想定してください。非常によく似たコンポーネントへの移行であっても、パディングや配置のデフォルト値は変わっています。移行前のスクリーンショットに人為的に一致させようとせず、Material3 のデフォルト値を優先してください。
機能 2:コンポーネントのサンプル
Wear Compose には、<artifact>-<version>-samples-sources.jar ファイルに、すべてのコンポーネントの個別サンプルが含まれています。compose-material3、compose-foundation、compose-navigation3 のいずれかを使用すると、Gradle はこれらの JAR ファイルをメインライブラリの JAR と一緒に自動的にダウンロードします。
Wear Compose Material3 のコンポーネントを追加または調整する場合は、常に正式なコンポーネントサンプルを使用してください。
厳格な遵守:抽出は任意ではありません。サンプルを抽出して読み込むまで、コードを実装することは禁止されています。別の検索ツールを使ったり、ライブラリのドキュメントだけで十分だと判断してこの手順を省略することは、プロトコル違反です。先に進む前にサンプルファイルを読み、ローカルキャッシュを検証する必要があります。
手順 1:準備
build.gradle.ktsまたはlibs.versions.tomlを確認し、Wear Compose のバージョンが{VERSION}と一致していることを確認します。- Gradle の同期を実行して、必要な依存関係がダウンロードされていることを確認します。
手順 2:ローカルキャッシュを確認
- キャッシュディレクトリのパスを定義します:
<SKILL_ROOT>/samples/{VERSION}/。別の場所を独自に選ばないでください。 - このディレクトリが存在し、
.ktファイルを含むサブディレクトリがあるか確認します。- はい(キャッシュヒット): 手順 4 に進みます。
- いいえ(キャッシュミス): 手順 3 に進みます。
手順 3:Gradle キャッシュを確認
-
サンプルソースは Gradle キャッシュに保存されています。時間のかかる総当たり検索を避けるため、次の手順を実行します。
- Gradle ユーザーホームを特定します(通常は
~/.gradleです。または$GRADLE_USER_HOMEを確認します)。 - キャッシュのルートは
<GRADLE_USER_HOME>/cachesです。これを<CACHE_ROOT>と呼びます。
- Gradle ユーザーホームを特定します(通常は
-
{ARTIFACT}をリスト["material3", "foundation"]の項目として定義します。androidx.wear.compose.navigation3ライブラリを使用している場合は、"navigation3" もリストに追加します。 -
リスト内の各
{ARTIFACT}について、次の手順を実行します。-
ライブラリの相対パス部分を次のように組み立てます:
androidx.wear.compose/compose-{ARTIFACT}/{VERSION}。 -
対象を絞った
findコマンドを実行します。効率を高めるための例を次に示します。find <CACHE_ROOT>/modules-2/files-2.1/androidx.wear.compose/compose-{ARTIFACT}/{VERSION}/ \ -name "*samples-sources.jar"
-
-
この JAR を正式なサンプルソースとして使用します。
-
各 JAR の内容を
unzip -jを使って<SKILL_ROOT>/samples/{VERSION}/{ARTIFACT}/に展開し、ディレクトリ構造をフラット化します。 -
手順 4 に直接進みます。
手順 4:サンプルを読み、実装する
- 関連する
.ktサンプルファイルを読みます。 - バージョンが一致するこれらの公式サンプルを、次の項目の信頼できる情報源として使用します。
- 必須パラメーターとスロット名。
- デフォルトのスタイル設定とタイポグラフィのトークン。
- インタラクティブな動作(例:
onClick、onLongClick)。 - コンポーネントのネスト(例:
AppScaffold->ScreenScaffold)。
機能 3:コンポーネントのガイダンス
必須:コンポーネントを使用する際は、この機能をチェックリストとして使用してください。コンポーネントの構文だけでなく、実際に各コンポーネントを使用する方法について、より包括的なガイダンスを提供します。
-
AppScaffoldとScreenScaffold- [ ] 外側のコンテナとして
AppScaffoldを使用し、その子要素としてScreenScaffoldを配置します。 - [ ]
AppScaffoldは1つだけ使用し、ScreenScaffoldは任意の数だけ使用します。
- [ ] 外側のコンテナとして
-
ScalingLazyColumn- 代わりにTransformingLazyColumnを使用します。 -
TransformingLazyColumn- 次のインポートが必要です:import androidx.wear.compose.foundation.lazy.TransformingLazyColumn import androidx.wear.compose.foundation.lazy.TransformingLazyColumnDefaults import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState // ... import androidx.wear.compose.material3.lazy.rememberTransformationSpec import androidx.wear.compose.material3.lazy.transformedHeight
標準的な例:
val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding), transformation = SurfaceTransformation(transformationSpec) ) { Text(text = "Header") } } // ... other items item { Button( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding), transformation = SurfaceTransformation(transformationSpec), onClick = { /* ... */ }, icon = { Icon( imageVector = Icons.Default.Build, contentDescription = "build", ) }, ) { Text( text = "Build", maxLines = 1, overflow = TextOverflow.Ellipsis, ) } } } }
- [ ]
ScalingLazyColumnの代わりにTransformingLazyColumnを使用します。 - [ ]
ScreenScaffoldからcontentPaddingパラメーターをTransformingLazyColumnに渡す必要があります。 - [ ] 必要な上下のパディングを設定するには、
minimumVerticalContentPadding修飾子を使用します。ButtonDefaults、CardDefaults、`ListHeaderDefaults など、デフォルト値のいずれかを指定します。- 注:これは
TransformingLazyColumnItemScope内で使用できるスコープ付き修飾子です。
- [ ] リストが形状を変化させながら拡大縮小することを確認します。
- [ ]
transformedHeight修飾子を使用します。 - [ ]
transform = SurfaceTransform(...)を使用します。 - [ ] リストでスナップを設定する場合は、
flingBehaviorとrotaryScrollableBehaviorを一緒に使用します:
val columnState = rememberTransformingLazyColumnState() ScreenScaffold(scrollState = columnState) { contentPadding -> TransformingLazyColumn( state = columnState, flingBehavior = TransformingLazyColumnDefaults.snapFlingBehavior(columnState), rotaryScrollableBehavior = RotaryScrollableDefaults.snapBehavior(columnState) ) { // ... // ... } }
- [ ]
-
ScreenScaffold- [ ]
!LocalScrollCaptureInProgress.currentを条件にしてscrollIndicatorを表示します。
- [ ]
-
EdgeButton- [ ]
TransformingLazyColumnの最後の項目として使用しないでください。代わりに、ScreenScaffoldのスロットを使用します。 - [ ]
TransformingLazyColumn内で使用する場合は、必要なオーバースクロール動作を追加します:
val columnState = rememberTransformingLazyColumnState() ScreenScaffold( scrollState = columnState, edgeButton = { EdgeButton( onClick = { /* TODO */ }, modifier = Modifier.scrollable( columnState, orientation = Orientation.Vertical, reverseDirection = true, // Apply overscroll to the EdgeButton for proper scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ) ) { Text("More") } } ) { contentPadding -> TransformingLazyColumn( contentPadding = contentPadding, state = columnState, ) { // ... // ... } }
- [ ]
-
Column- [ ] システムフォントを最大にしても画面がスクロールしない場合に限り、
ScreenScaffoldの直接の子要素として使用します。 - [ ] それ以外の場合は、代わりに
TransformingLazyColumnを使用します。
- [ ] システムフォントを最大にしても画面がスクロールしない場合に限り、
-
スタイル
- [ ] テキストサイズをハードコードしないでください。
MaterialThemeのtypographyを使用します。 - [ ] 色をハードコードしないでください。
MaterialThemeのcolorSchemeを使用します。
- [ ] テキストサイズをハードコードしないでください。
-
コンポーネントのデフォルト値を使用します:
- [ ]
Buttonなどのコンポーネントには、対応するButtonDefaultsオブジェクトがあります。 - パディングやスタイルの値を扱う際は、ハードコードされた値よりも、各コンポーネントの
*Defaultsオブジェクトを確認して使用してください。
- [ ]
-
Wear 固有のプレビューを使用します:
- [ ]
WearPreviewDevices - [ ]
WearPreviewFontScales
- [ ]
-
アンビエントモード
- [ ]
AmbientLifecycleObserverの代わりにLocalAmbientModeManagerを使用します。
- [ ]
-
ナビゲーション
- [ ] 新たにナビゲーションを追加する場合は、Navigation3 を使用します。
- [ ] Wear OS で Navigation3 を使用する場合は、Wear Compose の
compose-navigation3ライブラリにあるSwipeDismissableSceneStrategy()を使用します。