Material 3(以下、M3)のカラーテーマって複雑ですよね。自分の理解を進めるために、できるだけ整理してみます。もし間違っている部分があったら、Twitterなどで指摘していただけると助かります。
目次
カラーテーマの構成
まずはM3のカラーテーマがどのような要素で構成されているのか、使われる用語の意味も確認しながら整理します。
テーマとは
そもそもテーマとは、アプリのUIに一貫性を持たせるために定義する属性のことです。
カラースキーム、タイプグラフィー、シェイプで構成されます。
カラースキーム
よく見るこれのことです。
23種類のロールに割り当てた色の集合です。
ライトテーマとダークテーマで別々のカラースキームを設定するのが一般的です。
5つのキーカラーとエラーカラーからそれぞれトーンパレットを生成し、各トーンパレットから3~4色の色をピックアップしてロールに割り当て、カラースキームを構成します。
ロール
Primary, OnPrimary, PrimaryContainer, OnPrimaryContainerなど、カラースキームを構成する23種類の色の名前です。
“On”がつくロールは、同名のロールの上に文字やアイコンを配置するときに使います。例えばOnPrimaryはPrimaryの上に配置する文字やアイコンの色として使います。
キーカラー
トーンパレットを作成する基準になり、カラースキームを特徴づける色です。
キーカラーのうちPrimary、Secondary、Tertiaryの3色を「アクセントカラー」と呼び、Neutral、Neutral Variantの2色を「ニュートラルカラー」と呼びます。
Primary Color
UI全体を通して目立つ部分に使うキーカラーで、UIを特徴づける色となります。
Secondary Color
Primaryよりは目立たないが、色のバリエーションを広げるために使われます。
Tertiary Color
PrimaryとSecondaryのバランスをとったり、より高い注意を引かせたい部分に使ったりします。
Neutral Color
SurfaceやBackgroundとして、テキストやアイコンを目立たせたい部分で使います。
Neutral Variant Color
テキストやアイコンを控えめに見せたい部分のSurfaceに使います。
エラーカラー
エラー表示などに使うための色。通常は赤系の色になります。キーカラーと同じく、トーンパレットの基準になります。
トーンパレット
これです。
各キーカラーの色相(Hue)と彩度(Chroma)は変化させずに、輝度(Luminance)を0%(黒)から100%(白)まで変化させて作成した13種類の色の集合です。それぞれの色は、輝度のパーセンテージを使って、「Primary40」などのように呼びます。
このトーンパレットの中から、カラースキームのロールに割り当てます。キーカラーを元にアルゴリズム的にパレットを作成するため、キーカラーで指定した色は必ずしも実際のカラースキームには使われません。
カラースキームを作成する
ここまで読んでいただいた方は分かったと思いますが、独自のカラーテーマの作成とは、カラースキームを作成する作業にほかなりません。ここからは、WebのTheme Builderを使ってカラースキームを作成し、Jetpack ComposeのUIに適用するまでの手順を確認していきます。
Theme Builder
テーマの作成には、Webツールの「Material Theme Builder」が便利ですが、このほかにもFigmaのプラグインなんかもあります。
Material Theme BuilderのURLを開き、上部の「CUSTOM」をクリックします。
「Primary」の丸い部分をクリックし、Primary Key Colorを指定します。
Primary Key Colorを指定すると、トーンパレットが作成され、Primary, On Primaryなどの色が設定されます。また、SecondaryやTertiary、Neutralも連動して変化します。
必要に応じて、Secondary, Tertiary, Neutralも指定します。これらの色を指定するときは、上から順に指定する必要があることに注意してください。Secondaryを指定した後でPrimaryを指定すると、Primaryに合わせてアルゴリズムがSecondaryの色を変更してしまいます。TertiaryやNeutralも同様です。
希望のカラースキームができたら、右上の「EXPORT」をクリックし、Jetpack Composeをクリックすると、zipファイルをダウンロードできます。
プロジェクトに組み込む
ダウンロードしたzipファイルには、Color.kt
とTheme.kt
が含まれています。これらをAndroid Studioのプロジェクトに組み込めば、作成したカラースキームを適用できます。
プロジェクト作成時にEmpty Compose Activity
のテンプレートを使った場合は、プロジェクトにすでにColor.kt
とTheme.kt
が存在しています。ここに、ダウンロードしたファイルの内容を組み込みます。
Color.kt
Color.kt
は単なる色の定義の羅列ですので、ダウンロードしたファイルに含まれている定義を単純にコピペでOKです。既存プロジェクトがM3の場合は、同じ名前が既に定義されているかもしれないので、上書きします。もともとがM2の場合は、単純に定義を追加する形で問題ないと思います。
val md_theme_light_primary = Color(0xFF166d21)
val md_theme_light_onPrimary = Color(0xFFffffff)
val md_theme_light_primaryContainer = Color(0xFFa0f799)
val md_theme_light_onPrimaryContainer = Color(0xFF002202)
val md_theme_light_secondary = Color(0xFF52634e)
val md_theme_light_onSecondary = Color(0xFFffffff)
val md_theme_light_secondaryContainer = Color(0xFFd5e8ce)
val md_theme_light_onSecondaryContainer = Color(0xFF101f0f)
val md_theme_light_tertiary = Color(0xFF38656a)
val md_theme_light_onTertiary = Color(0xFFffffff)
val md_theme_light_tertiaryContainer = Color(0xFFbcebf0)
val md_theme_light_onTertiaryContainer = Color(0xFF011f22)
val md_theme_light_error = Color(0xFFba1b1b)
val md_theme_light_errorContainer = Color(0xFFffdad4)
val md_theme_light_onError = Color(0xFFffffff)
val md_theme_light_onErrorContainer = Color(0xFF410001)
val md_theme_light_background = Color(0xFFfcfdf6)
val md_theme_light_onBackground = Color(0xFF1a1c19)
val md_theme_light_surface = Color(0xFFfcfdf6)
val md_theme_light_onSurface = Color(0xFF1a1c19)
val md_theme_light_surfaceVariant = Color(0xFFdee5d8)
val md_theme_light_onSurfaceVariant = Color(0xFF424840)
val md_theme_light_outline = Color(0xFF73796f)
val md_theme_light_inverseOnSurface = Color(0xFFf1f1eb)
val md_theme_light_inverseSurface = Color(0xFF2f312d)
val md_theme_light_inversePrimary = Color(0xFF85da80)
val md_theme_light_shadow = Color(0xFF000000)
val md_theme_dark_primary = Color(0xFF85da80)
val md_theme_dark_onPrimary = Color(0xFF003907)
val md_theme_dark_primaryContainer = Color(0xFF00530d)
val md_theme_dark_onPrimaryContainer = Color(0xFFa0f799)
val md_theme_dark_secondary = Color(0xFFbaccb3)
val md_theme_dark_onSecondary = Color(0xFF253423)
val md_theme_dark_secondaryContainer = Color(0xFF3c4b39)
val md_theme_dark_onSecondaryContainer = Color(0xFFd5e8ce)
val md_theme_dark_tertiary = Color(0xFFa1cfd4)
val md_theme_dark_onTertiary = Color(0xFF00363b)
val md_theme_dark_tertiaryContainer = Color(0xFF1e4d52)
val md_theme_dark_onTertiaryContainer = Color(0xFFbcebf0)
val md_theme_dark_error = Color(0xFFffb4a9)
val md_theme_dark_errorContainer = Color(0xFF930006)
val md_theme_dark_onError = Color(0xFF680003)
val md_theme_dark_onErrorContainer = Color(0xFFffdad4)
val md_theme_dark_background = Color(0xFF1a1c19)
val md_theme_dark_onBackground = Color(0xFFe2e3dd)
val md_theme_dark_surface = Color(0xFF1a1c19)
val md_theme_dark_onSurface = Color(0xFFe2e3dd)
val md_theme_dark_surfaceVariant = Color(0xFF424840)
val md_theme_dark_onSurfaceVariant = Color(0xFFc2c8bd)
val md_theme_dark_outline = Color(0xFF8c9288)
val md_theme_dark_inverseOnSurface = Color(0xFF1a1c19)
val md_theme_dark_inverseSurface = Color(0xFFe2e3dd)
val md_theme_dark_inversePrimary = Color(0xFF166d21)
val md_theme_dark_shadow = Color(0xFF000000)
Theme.kt
ダウンロードしたTheme.kt
には、ライトテーマ用とダークテーマ用のカラースキームの定義と、それらを端末の設定に合わせて切り替える処理が含まれています。
private val LightThemeColors = lightColorScheme(
primary = md_theme_light_primary,
onPrimary = md_theme_light_onPrimary,
primaryContainer = md_theme_light_primaryContainer,
onPrimaryContainer = md_theme_light_onPrimaryContainer,
secondary = md_theme_light_secondary,
onSecondary = md_theme_light_onSecondary,
secondaryContainer = md_theme_light_secondaryContainer,
onSecondaryContainer = md_theme_light_onSecondaryContainer,
tertiary = md_theme_light_tertiary,
onTertiary = md_theme_light_onTertiary,
tertiaryContainer = md_theme_light_tertiaryContainer,
onTertiaryContainer = md_theme_light_onTertiaryContainer,
error = md_theme_light_error,
errorContainer = md_theme_light_errorContainer,
onError = md_theme_light_onError,
onErrorContainer = md_theme_light_onErrorContainer,
background = md_theme_light_background,
onBackground = md_theme_light_onBackground,
surface = md_theme_light_surface,
onSurface = md_theme_light_onSurface,
surfaceVariant = md_theme_light_surfaceVariant,
onSurfaceVariant = md_theme_light_onSurfaceVariant,
outline = md_theme_light_outline,
inverseOnSurface = md_theme_light_inverseOnSurface,
inverseSurface = md_theme_light_inverseSurface,
inversePrimary = md_theme_light_inversePrimary,
)
private val DarkThemeColors = darkColorScheme(
primary = md_theme_dark_primary,
onPrimary = md_theme_dark_onPrimary,
primaryContainer = md_theme_dark_primaryContainer,
onPrimaryContainer = md_theme_dark_onPrimaryContainer,
secondary = md_theme_dark_secondary,
onSecondary = md_theme_dark_onSecondary,
secondaryContainer = md_theme_dark_secondaryContainer,
onSecondaryContainer = md_theme_dark_onSecondaryContainer,
tertiary = md_theme_dark_tertiary,
onTertiary = md_theme_dark_onTertiary,
tertiaryContainer = md_theme_dark_tertiaryContainer,
onTertiaryContainer = md_theme_dark_onTertiaryContainer,
error = md_theme_dark_error,
errorContainer = md_theme_dark_errorContainer,
onError = md_theme_dark_onError,
onErrorContainer = md_theme_dark_onErrorContainer,
background = md_theme_dark_background,
onBackground = md_theme_dark_onBackground,
surface = md_theme_dark_surface,
onSurface = md_theme_dark_onSurface,
surfaceVariant = md_theme_dark_surfaceVariant,
onSurfaceVariant = md_theme_dark_onSurfaceVariant,
outline = md_theme_dark_outline,
inverseOnSurface = md_theme_dark_inverseOnSurface,
inverseSurface = md_theme_dark_inverseSurface,
inversePrimary = md_theme_dark_inversePrimary,
)
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
val colors = if (!useDarkTheme) {
LightThemeColors
} else {
DarkThemeColors
}
MaterialTheme(
colorScheme = colors,
typography = AppTypography,
content = content
)
}
Jetpack Composeプロジェクトの場合、XxxTheme()
(Xxxはプロジェクト名)という関数がすでに用意されているはずですので、その中身をダウンロードしたAppTheme()
に置き換えます。
M2のプロジェクトをM3に移行する場合は、依存関係の変更などいくつか対応が必要になります。そのあたりは「Jetpack ComposeアプリをMaterial Design 3へ移行する」にまとめてありますので、参考にしてください。
また、ダウンロードしたTheme.kt
には、カスタムカラーについての定義も含まれています。カスタムカラーを使用する場合はこれらもコピーします。
補足
Material Designはあくまでガイドラインであって、絶対に守らなければならないものではないです。Theme Builderで作成したテーマが気に入らないので、一部の色だけ変更したい、ということもあると思います。個人的には、指定したKey Colorが実際のアプリのUIには使われない(Key Colorを元に生成したカラーパレットから、決められた輝度の色が使われるため)点が微妙だなあと思います。
そういった場合には、Theme Builderで作成してダウンロードしたソースコードの一部を変更して使うことになると思います。その時は、コンテナとコンテンツの関係になって(入れ子になって)使われる可能性のあるロール同士のコントラストが確保されるよう注意します。そういったロールの組み合わせはMaterial Design 3のColor Themingページに記載されています。
参考
この記事を書くにあたって、下記のサイトを参考にしました。