styles について
Jetpack ComposeのカスタムコンポーネントとテーマをStyles APIへ移行するスキルです。スタイル定義、状態管理、表示検証を扱います。実験的機能で、Composeのalpha APIが必要です。Material Designコンポーネントのスタイルには対応しません。
主な機能
- 01テーマ構成とデザイントークンを分析
- 02ComponentStylesを作成してカスタムテーマに接続
- 03コンポーネントをStyles APIへ移行
- 04インタラクション状態とModifier.styleable()を処理
- 05スクリーンショットとUIテストで表示を検証
活用シーン
- 01カスタムコンポーネントのスタイル引数をStyleへ移行
- 02デザイントークンをコンポーネントスタイルに集約
- 03スタイル移行後の表示崩れを確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ android/ skills --skill stylesインストール後、Claude Code で/stylesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/android/develop/ui/compose/designsystems/custom.mdreferences/android/develop/ui/compose/styles/fundamentals.mdstate-animations.mdstyles-vs-modifiers.mdtheming.md詳細
制限事項
- このスキルは EXPERIMENTAL であり、Compose をアルファ版に更新して Experimental API をオプトインする必要があることをユーザーに警告してください。
- このスキルはカスタム UI コンポーネントとカスタムテーマのみをサポートします。
- このスキルは Material Design コンポーネントの Style をサポートしません。
前提条件
1. 依存関係をアップグレードする
- プロジェクトでは
compileSdkバージョン 37 以降を使用する必要があります。 - プロジェクトでは
androidx.compose.foundation:foundationバージョン1.12.0-alpha01以降を使用する必要があります。 - または、プロジェクトでは Compose BOM バージョン
2026.04.01以降を使用する必要があります。 - API では次のパッケージを正確に指定する必要があります:
import androidx.compose.foundation.style.Style
2. 実験的 API を有効にするコンパイラーオプションを設定する
プロジェクトレベルで実験的 API をオプトインする必要があります。次のブロックをモジュールの build.gradle.kts に追加してください。
kotlin {
compilerOptions {
jvmTarget = JvmTarget.fromTarget("17")
freeCompilerArgs.add("-opt-in=androidx.compose.foundation.style.ExperimentalFoundationStyleApi")
}
}
主なワークフローとガイド
特定の開発タスクを完了するには、公式ドキュメントを参照してください。
- Style の基本的な使い方:コンポーネントの背景、サイズ、配置を設定するには、Compose Styles の基礎ガイド に従ってください。
- 状態とトランジション:押下時やホバー時など、状態の変化に応じたプロパティの変更を設定するには、アニメーションと状態に基づくスタイリングの ガイドに従ってください。
- アーキテクチャ上のトレードオフ:Style と標準の Modifier のどちらを使うか判断するには、Styles と Modifiers の 比較を参照してください。
- テーマレベルの統合:スタイル定義をカスタムテーマに接続するには、Styles を使ったテーマ設定とCompose のカスタムテーマを参照してください。
段階的な移行ワークフロー
ステップ 1:テーマ構造を分析する
- 中心となるテーマファイル(
Theme.ktなど)を探します。 - デザイントークンを特定します。色、タイポグラフィ、シェイプの参照(
LocalColorScheme、LocalTypography、LocalShapesなど)を書き留めます。 - プロジェクトに Jetpack Compose の依存関係がない場合は、作業を中止します。まず Jetpack Compose に移行するようユーザーに指示してください。
- プロジェクトが
androidx.compose.material.MaterialThemeをインポートしている場合は、続行する前に Material 3 への移行を推奨してください。
ステップ 2:ComponentStyles を作成する
-
テーマディレクトリに
ComponentStyles.ktという名前の新しいファイルを作成します。 -
コンポーネントのスタイルを格納するトップレベルのデータクラスを定義します。たとえば、Jetsnack では
JetsnackStylesという名前です。object ExampleComponentStyles { val customButtonStyle: Style = { } val customTextFieldStyle: Style = { } }
-
このクラスは静的な参照を使ってカスタムテーマから公開します。ここでは必要ないため、
CompositionLocalsは使用しないでください。@Immutable class JetsnackTheme( // other Design system properties ) { companion object { val colors: CustomThemingWithStyles.JetsnackColors @Composable @ReadOnlyComposable get() = LocalJetsnackTheme.current.colors // ... // add helper static reference val styles: ComponentStyles = ComponentStyles } }
-
CompositionLocalsを使って公開している場合は、テーマトークンを直接参照するStyleScopeの拡張機能を用意します。例:val StyleScope.colors: JetsnackColors get() = LocalJetsnackTheme.currentValue.colors val StyleScope.typography: androidx.compose.material3.Typography get() = LocalJetsnackTheme.currentValue.typography val StyleScope.shapes: Shapes get() = LocalJetsnackTheme.currentValue.shapes
ステップ 3:コンポーネントを Styles API に移行する
カスタムコンポーネント(例:CustomButton)ごとに、次の手順を完了してください。
- 視覚的なベースラインを確立する(エミュレーターが利用できる場合):
- Android エミュレーターを実行できない場合: この手順全体をスキップして、ステップ 2 に進んでください。
- Android エミュレーターを実行できる場合: ベースラインのスクリーンショットを取得するため、次のいずれかを実施してください。
- オプション A: コンポーネントの既存のスクリーンショットテストを探して実行します。
- オプション B(テストが存在しない場合): プロジェクトで既に使用しているテストフレームワークを使ってテストを作成し、実行します。
- オプション C(フレームワークが存在しない場合): UI Automator または Espresso を使って最小限のスクリーンショットテストを作成し、実行します。
- 個別のスタイル設定パラメーターを削除します:シグネチャから
backgroundColor、shape、textStyle、contentPaddingなど、StyleScopeがサポートするスタイル設定パラメーターを削除します。 - スタイルパラメーターを追加します:関数シグネチャに
style: Style = Styleを追加します。デフォルト値が必ずStyleであることを確認してください(例:style: Style = Style)。ChipStyleDefaultなど、特定のスタイルをデフォルト値にしないでください。 - 状態の追跡を宣言します:コンポーネントが操作可能な場合は、インタラクションソースを使って
MutableStyleStateを作成します。Composable 内でisEnabledなどの状態フィールドを更新し、状態を正しく追跡してください。 - スタイル適用可能なモディファイアを適用します:ルート要素の個別のレイアウトモディファイアを
Modifier.styleable()に置き換えます。 - デフォルト値を ComponentStyles に移動します:コンポーネント定義内のハードコードされた値を、
ComponentStyles.ktの専用のStyleインスタンスに移動します。 - コンポーネントを検証します: 最初に取得したベースラインのスクリーンショット画像と、新しい Composable のレンダリング済み Compose Preview を比較します。文字列の内容は無視し、レイアウトとスタイルに注目してください。見た目が一致するまで Compose コードを調整します。確認できたら、新しい Composable の Compose UI テストを作成します。
移行例
移行前:
@Composable
fun CustomButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
backgroundColor: Color = JetsnackTheme.colors.brandLight,
disabledBackgroundColor: Color = JetsnackTheme.colors.brandSecondary,
shape: Shape = JetsnackTheme.shapes.extraLarge,
textStyle: TextStyle = JetsnackTheme.typography.labelLarge,
enabled: Boolean = true,
content: @Composable RowScope.() -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
Row(
modifier
.clickable(onClick = onClick, indication = null, interactionSource = interactionSource)
.background(if (enabled) backgroundColor else disabledBackgroundColor, shape)
.defaultMinSize(58.dp, 40.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content,
)
}
移行後:
// Exposed via ComponentStyles.kt
object ComponentStyles {
val buttonStyle = Style {
background(colors.brandLight)
shape(shapes.extraLarge)
minWidth(58.dp)
minHeight(40.dp)
textStyle(typography.labelLarge)
disabled {
background(colors.brandSecondary)
}
}
}
@Composable
fun CustomButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
style: Style = Style,
enabled: Boolean = true,
content: @Composable RowScope.() -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
val styleState = rememberUpdatedStyleState(interactionSource) {
it.isEnabled = enabled
}
Row(
modifier
.clickable(onClick = onClick, indication = null, interactionSource = interactionSource)
.styleable(styleState, JetsnackTheme.styles.buttonStyle, style),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content,
)
}
ステップ 4:変更を検証する
- プロジェクトをビルドします。コンパイルエラーがないことを確認してください。
- モジュールのスクリーンショットテストを実行します。
- 更新前と更新後のコンポーネントを使ったアプリ全体の見た目を比較します。レイアウトに視覚的なリグレッションが発生していないことを確認してください。
コメント
Markdown 対応