Jetpack Compose には、デジタル インターフェースを作成するための包括的なデザイン システムであるマテリアル デザインの実装が用意されています。マテリアル デザインのコンポーネント(ボタン、カード、スイッチなど)は、プロダクトのブランドをより良く反映するようにマテリアル デザインをカスタマイズする体系的な方法である、マテリアル テーマ設定に基づいて構築されています。マテリアル テーマには、色、タイポグラフィ、シェイプの属性が含まれています。これらの属性をカスタマイズすると、その変更内容は、アプリのビルドに使用するコンポーネントに自動的に反映されます。
Jetpack Compose は、MaterialTheme コンポーザブルを使用して、こうしたコンセプトを実装します。
MaterialTheme( colors = // ... typography = // ... shapes = // ... ) { // app content }
MaterialTheme に渡すパラメータを構成して、アプリのテーマを設定します。
色
Compose では、データ保持クラスである Color クラスを使用して色をモデル化します。
val Red = Color(0xffff0000) val Blue = Color(red = 0f, green = 0f, blue = 1f)
これらはどのように整理してもかまいませんが(最上位の定数として、シングルトン内で、またはインラインで定義)、テーマで色を指定し、そこから色を取得することを強くおすすめします。このアプローチにより、ダークモードとネストされたテーマをサポートできます。
Compose には、マテリアル カラーシステムをモデル化するための Colors クラスが用意されています。Colors は、ライトカラーまたはダークカラーのセットを作成するビルダー関数を提供します。
private val Yellow200 = Color(0xffffeb46) private val Blue200 = Color(0xff91a4fc) // ... private val DarkColors = darkColors( primary = Yellow200, secondary = Blue200, // ... ) private val LightColors = lightColors( primary = Yellow500, primaryVariant = Yellow400, secondary = Blue700, // ... )
Colors を定義したら、MaterialTheme に渡すことができます。
MaterialTheme( colors = if (darkTheme) DarkColors else LightColors ) { // app content }
テーマカラーを使用する
MaterialTheme.colors を使用すると、MaterialTheme コンポーザブルに提供されている Colors を取得できます。
Text( text = "Hello theming", color = MaterialTheme.colors.primary )
サーフェスとコンテンツの色
多くのコンポーネントは、色とコンテンツ色のペアを受け入れます。
Surface( color = MaterialTheme.colors.surface, contentColor = contentColorFor(color), // ... ) { /* ... */ } TopAppBar( backgroundColor = MaterialTheme.colors.primarySurface, contentColor = contentColorFor(backgroundColor), // ... ) { /* ... */ }
これにより、コンポーザブルの色を設定するだけでなく、その中に含まれるコンポーザブルであるコンテンツのデフォルト色を指定できます。多くのコンポーザブルは、デフォルトでこのコンテンツ色を使用します。たとえば、Text の色は親のコンテンツ色に基づき、Icon はその色を使用して色合いを設定します。
contentColorFor() メソッドは、テーマカラーに適した「on」色を取得します。たとえば、Surface に primary の背景色を設定すると、この関数を使用して onPrimary をコンテンツ色として設定します。テーマ以外の背景色を設定する場合は、適切なコンテンツ色も指定する必要があります。LocalContentColor を使用して、階層内の特定の位置にある現在の背景の推奨コンテンツ色を取得します。
コンテンツのアルファ版
重要度を伝え、視覚的な階層を提供するために、コンテンツを強調する度合いを変化させることがよくあります。マテリアル デザインのテキストの読みやすさに関する推奨事項では、異なるレベルの不透明度を利用してさまざまな重要度レベルを示すことを推奨しています。
Jetpack Compose は LocalContentAlpha を使用して、これを実装します。この CompositionLocal に値を指定することで、階層のコンテンツのアルファを指定できます。ネストされたコンポーザブルは、この値を使用してコンテンツにアルファ処理を適用できます。たとえば、Text と Icon は、LocalContentAlpha を使用するように調整された LocalContentColor の組み合わせをデフォルトで使用します。マテリアルは、ContentAlpha オブジェクトによってモデル化される一部の標準的なアルファ値(high、medium、disabled)を指定します。
// By default, both Icon & Text use the combination of LocalContentColor & // LocalContentAlpha. De-emphasize content by setting content alpha CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text( // ... ) } CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { Icon( // ... ) Text( // ... ) }
CompositionLocal の詳細については、CompositionLocal を使用したローカル スコープのデータをご覧ください。
ContentAlpha.high が使用されています。2 行目には重要度の低いメタデータが含まれているため、ContentAlpha.medium を使用します。ダークモード
Compose では、MaterialTheme コンポーザブルにさまざまな Colors のセットを指定することで、ライトテーマとダークテーマを実装します。
@Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { MaterialTheme( colors = if (darkTheme) DarkColors else LightColors, /*...*/ content = content ) }
この例では、MaterialTheme は独自のコンポーズ可能な関数でラップされています。この関数は、ダークモードを使用するかどうかを指定するパラメータを受け取ります。この場合、関数はデバイスのテーマ設定をクエリすることで、darkTheme のデフォルト値を取得します。
次のようなコードを使用すると、現在の Colors がライトテーマかダークテーマかを確認できます。
val isLightTheme = MaterialTheme.colors.isLight Icon( painterResource( id = if (isLightTheme) { R.drawable.ic_sun_24 } else { R.drawable.ic_moon_24 } ), contentDescription = "Theme" )
エレベーション オーバーレイ
マテリアルでは、ダークモードでエレベーションの高いサーフェスにエレベーション オーバーレイが適用され、背景が明るくなります。サーフェスの標高が高いほど(暗黙の光源に近づくほど)、サーフェスは明るくなります。
Surface コンポーザブルは、暗い色を使用するときにこれらのオーバーレイを自動的に適用します。サーフェスを使用する他のマテリアル コンポーザブルも同様です。
Surface( elevation = 2.dp, color = MaterialTheme.colors.surface, // color will be adjusted for elevation /*...*/ ) { /*...*/ }
surface 色が使用されています。カードとボトム ナビゲーションは背景よりも高い標高レベルにあるため、色がわずかに異なります。カードは背景よりも明るく、ボトム ナビゲーションはカードよりも明るくなっています。Surface を含まないカスタム シナリオの場合は、LocalElevationOverlay を使用します。これは、Surface コンポーネントで使用される ElevationOverlay を含む CompositionLocal です。
// Elevation overlays // Implemented in Surface (and any components that use it) val color = MaterialTheme.colors.surface val elevation = 4.dp val overlaidColor = LocalElevationOverlay.current?.apply( color, elevation )
標高オーバーレイを無効にするには、コンポーザブル階層の選択したポイントで null を指定します。
MyTheme { CompositionLocalProvider(LocalElevationOverlay provides null) { // Content without elevation overlays } }
限定的なカラー アクセント
マテリアルでは、ほとんどの場合、primary 色よりも surface 色を優先して使用することで、ダークモードに限定的な色のアクセントを適用することを推奨しています。TopAppBar や BottomNavigation などのマテリアル コンポーザブルは、デフォルトでこの動作を実装しています。
カスタム シナリオでは、primarySurface 拡張プロパティを使用します。
Surface( // Switches between primary in light theme and surface in dark theme color = MaterialTheme.colors.primarySurface, /*...*/ ) { /*...*/ }
タイポグラフィ
マテリアルでは、タイプシステムが定義されており、意味する内容に基づいて名付けられたスタイルを少数使用することが推奨されています。
Compose は、Typography クラス、TextStyle クラス、フォント関連クラスを使用して型システムを実装します。Typography コンストラクタにはスタイルごとにデフォルトが用意されているため、カスタマイズしないものは省略できます。
val raleway = FontFamily( Font(R.font.raleway_regular), Font(R.font.raleway_medium, FontWeight.W500), Font(R.font.raleway_semibold, FontWeight.SemiBold) ) val myTypography = Typography( h1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W300, fontSize = 96.sp ), body1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W600, fontSize = 16.sp ) /*...*/ ) MaterialTheme(typography = myTypography, /*...*/) { /*...*/ }
全体で同じ書体を使用する場合は、defaultFontFamily パラメータを指定し、TextStyle 要素の fontFamily を省略します。
val typography = Typography(defaultFontFamily = raleway) MaterialTheme(typography = typography, /*...*/) { /*...*/ }
テキスト スタイルを使用する
TextStyle 要素には MaterialTheme.typography を使用してアクセスします。次のように TextStyle 要素を取得します。
Text( text = "Subtitle2 styled", style = MaterialTheme.typography.subtitle2 )
図形
マテリアルではシェイプ システムが定義されており、大、中、小のコンポーネントのシェイプを定義できます。
Compose は Shapes クラスでシェイプ システムを実装します。これにより、サイズ カテゴリごとに CornerBasedShape を指定できます。
val shapes = Shapes( small = RoundedCornerShape(percent = 50), medium = RoundedCornerShape(0f), large = CutCornerShape( topStart = 16.dp, topEnd = 0.dp, bottomEnd = 0.dp, bottomStart = 16.dp ) ) MaterialTheme(shapes = shapes, /*...*/) { /*...*/ }
多くのコンポーネントで、こうしたシェイプがデフォルトで使用されます。たとえば、Button、TextField、FloatingActionButton はデフォルトで small、AlertDialog はデフォルトで medium、ModalDrawer はデフォルトで large になります。完全なマッピングについては、シェイプ スキームの参照をご覧ください。
図形を使用する
Shape 要素には MaterialTheme.shapes を使用してアクセスします。次のようなコードで Shape 要素を取得します。
Surface( shape = MaterialTheme.shapes.medium, /*...*/ ) { /*...*/ }
デフォルト スタイル
Compose には、Android View のデフォルト スタイルに相当するコンセプトはありません。Material コンポーネントをラップする独自の overload コンポーザブル関数を作成することで、同様の機能を提供できます。たとえば、ボタンのスタイルを作成するには、独自のコンポーズ可能な関数でボタンをラップし、変更したいパラメータを直接設定して、他のパラメータをコンテナ コンポーザブルのパラメータとして公開します。
@Composable fun MyButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary ), onClick = onClick, modifier = modifier, content = content ) }
テーマ オーバーレイ
Compose で Android View のテーマ オーバーレイと同等のものを実現するには、MaterialTheme コンポーザブルをネストします。MaterialTheme は色、タイポグラフィ、シェイプをデフォルトで現在のテーマ値に設定するため、テーマでこれらのパラメータのいずれか 1 つのみが設定されている場合、他のすべてのパラメータはデフォルト値を保持します。
また、View ベースの画面を Compose に移行する場合は、android:theme 属性の使い方に注意してください。Compose UI ツリーの該当部分に新しい MaterialTheme が必要になる場合があります。
この例では、詳細画面の大部分に PinkTheme を使用し、関連セクションに BlueTheme を使用しています。次のスクリーンショットとコードは、このコンセプトを示しています。
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
コンポーネントの状態
クリックや切り替えなど、操作可能なマテリアル コンポーネントには、さまざまな視覚状態が存在します。状態には「enabled」、「disabled」、「press」などがあります。
コンポーザブルには、多くの場合 enabled パラメータが含まれます。false に設定すると、操作ができなくなり、色やエレベーションなどのプロパティが変更され、コンポーネントの状態を視覚的に伝えることができます。
enabled = true(左)と enabled = false(右)のボタン。ほとんどの場合、色や標高などの値にはデフォルトを使用できます。さまざまな状態で使用される値を構成する必要がある場合は、クラスとコンビニエンス関数を使用できます。次のボタンの例を考えてみましょう。
Button( onClick = { /* ... */ }, enabled = true, // Custom colors for different states colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary, disabledBackgroundColor = MaterialTheme.colors.onBackground .copy(alpha = 0.2f) .compositeOver(MaterialTheme.colors.background) // Also contentColor and disabledContentColor ), // Custom elevation for different states elevation = ButtonDefaults.elevation( defaultElevation = 8.dp, disabledElevation = 2.dp, // Also pressedElevation ) ) { /* ... */ }
enabled = true(左)と enabled = false(右)のボタン。色と標高の値を調整しています。Ripples
マテリアル コンポーネントは、リップルを使用して操作中であることを示します。階層で MaterialTheme を使用している場合、Ripple は clickable や indication などの修飾子内のデフォルトの Indication として使用されます。
ほとんどの場合、デフォルトの Ripple を使用できます。外観を構成する必要がある場合は、RippleTheme を使用して、色やアルファなどのプロパティを変更できます。
RippleTheme を拡張して、defaultRippleColor ユーティリティ関数と defaultRippleAlpha ユーティリティ関数を利用できます。次に、LocalRippleTheme を使用して、階層内でカスタム リップルテーマを指定します。
@Composable fun MyApp() { MaterialTheme { CompositionLocalProvider( LocalRippleTheme provides SecondaryRippleTheme ) { // App content } } } @Immutable private object SecondaryRippleTheme : RippleTheme { @Composable override fun defaultColor() = RippleTheme.defaultRippleColor( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) @Composable override fun rippleAlpha() = RippleTheme.defaultRippleAlpha( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) }
RippleConfiguration を使用して異なるリップル値を指定したボタン。詳細
Compose のマテリアル テーマ設定の詳細については、以下の参考情報をご覧ください。
Codelab
動画
あなたへのおすすめ
- 注: JavaScript がオフになっている場合はリンクテキストが表示されます
- Compose のカスタム デザイン システム
- Compose でマテリアル 2 からマテリアル 3 に移行する
- Compose のユーザー補助