Compose 内のマテリアル テーマ設定

Jetpack Compose には、デジタル インターフェースを作成するための包括的なデザイン システムであるマテリアル デザインの実装が用意されています。マテリアル デザインのコンポーネント(ボタン、カード、スイッチなど)は、マテリアル テーマ設定に基づいて構築されています。これは、マテリアル デザインをカスタマイズしてプロダクトのブランドを適切に反映するための体系的な方法です。マテリアル テーマは、タイポグラフィシェイプの属性で構成されています。これらの属性をカスタマイズすると、その変更内容はアプリのビルドに使用するコンポーネントに自動的に反映されます。

Jetpack Compose は、MaterialTheme コンポーザブルを使用して、こうしたコンセプトを実装します。

MaterialTheme(
    colors = …,
    typography = …,
    shapes = …
) {
    // app content
}

MaterialTheme に渡すパラメータを構成して、アプリのテーマを設定します。

対照的な 2 つのスクリーンショット。1 つ目のスクリーンショットはデフォルトの MaterialTheme スタイリングを使用し、2 つ目のスクリーンショットは変更したスタイリングを使用しています。

図 1. 1 つ目のスクリーンショットは MaterialTheme を構成していないアプリを示しています。そのため、デフォルトのスタイリングが使用されています。2 つ目のスクリーンショットは、スタイリングをカスタマイズするために MaterialTheme にパラメータを渡すアプリを示しています。

Compose では、色はシンプルなデータ保持クラスである Color クラスによってモデル化されます。

val Red = Color(0xffff0000)
val Blue = Color(red = 0f, green = 0f, blue = 1f)

これらはどのように整理してもかまいませんが(最上位の定数として、シングルトン内で、またはインラインで定義)、テーマで色を指定し、そこから色を取得することを強くおすすめします。この方法により、ダークテーマやネストされたテーマを簡単にサポートできます。

テーマのカラーパレットの例

図 2. マテリアル カラーシステム。

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: Color = MaterialTheme.colors.surface,
    contentColor: Color = contentColorFor(color),
    // ...

TopAppBar(
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    // ...

これにより、コンポーザブルの色を設定するだけでなく、コンテンツ(コンポーザブルの中に含まれるコンポーザブル)のデフォルト色も指定できます。多くのコンポーザブルは、デフォルトでこのコンテンツ色を使用します。たとえば、Text の色は親のコンテンツ色に基づき、Icon はその色を使用して色合いを設定します。

同じバナーで色が異なる 2 つの例

図 3. 異なる背景色を設定すると、テキストとアイコンが異なる色になります。

contentColorFor() メソッドは、テーマカラーに適した「on」色を取得します。たとえば、Surfaceprimary の背景色を設定すると、この関数を使用して onPrimary がコンテンツ色として設定されます。テーマ以外の背景色を設定する場合は、適切なコンテンツ色も指定する必要があります。現在の背景で優先するコンテンツ色を取得するには、階層内の特定の位置で LocalContentColor を使用します。

コンテンツのアルファ版

重要度を伝え、視覚的な階層を提供するために、コンテンツを強調する度合いを変化させることがよくあります。マテリアル デザインのテキストの読みやすさに関する推奨事項では、異なるレベルの透明度を利用してさまざまな重要度レベルを示すことを推奨しています。

Jetpack Compose は LocalContentAlpha を介して、これを実装します。この CompositionLocal に値を指定することで、階層のコンテンツのアルファ版を指定できます。ネストされたコンポーザブルは、この値を使用してコンテンツにアルファ処理を適用できます。たとえば、TextIcon は、LocalContentColor を使用するように調整された LocalContentAlpha の組み合わせをデフォルトで使用します。マテリアルは、ContentAlpha オブジェクトによってモデル化される一部の標準的なアルファ値(highmediumdisabled)を指定します。

// 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 でローカルにスコープ設定されたデータについてのガイドをご覧ください。

さまざまなレベルのテキスト強調を示す、記事タイトルのスクリーンショット

図 4. テキストにさまざまなレベルの強調を適用して、情報の階層を視覚的に伝えます。テキストの最初の行はタイトルで、最も重要な情報があるため、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_24dp
        } else {
          R.drawable.ic_moon_24dp
        }
    ),
    contentDescription = "Theme"
)

エレベーション オーバーレイ

マテリアルでは、エレベーションの高いダークテーマのサーフェスは、背景を明るくするエレベーション オーバーレイを受け取ります。サーフェスのエレベーションが高くなるほど(暗黙的な光源に近づくほど)、サーフェスは明るくなります。

こうしたオーバーレイは、暗い色を使用している場合や、サーフェスを使用するその他のマテリアル コンポーザブルの場合、Surface コンポーザブルによって自動的に実装されます。

Surface(
    elevation = 2.dp,
    color = MaterialTheme.colors.surface, // color will be adjusted for elevation
    /*...*/
) { /*...*/ }

エレベーション レベルの異なる要素に使用される、微妙に異なる色を示すアプリのスクリーンショット

図 5. カードとボトム ナビゲーションはどちらも背景として surface 色が使用されています。カードとボトム ナビゲーションは背景よりレベルが高い異なるエレベーションに存在するため、色がわずかに異なります。カードは背景よりも明るく、ボトム ナビゲーションはカードよりも明るくなります。

Surface を含まないカスタム シナリオの場合、Surface コンポーネントによって使用される ElevationOverlay を含む CompositionLocalLocalElevationOverlay を使用します。

// 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 カラーの使用を優先することで、ダークテーマに限定的なカラー アクセントを適用することをおすすめします。TopAppBarBottomNavigation などのマテリアル コンポーザブルは、デフォルトでこの動作を実装しています。

図 6. 限定的なカラー アクセントを使用したマテリアル ダークテーマ。上部のアプリバーは、ライトテーマでプライマリ色を使用し、ダークテーマでサーフェス色を使用しています。

カスタム シナリオでは、primarySurface 拡張プロパティを使用します。

Surface(
    // Switches between primary in light theme and surface in dark theme
    color = MaterialTheme.colors.primarySurface,
    /*...*/
) { /*...*/ }

タイポグラフィ

マテリアルはタイプシステムを定義し、意味的に名前をつけたスタイルを少数使用するよう推奨しています。

さまざまなスタイルの各種書体の例

図 7. マテリアルのタイプシステム。

Compose は、TypographyTextStyleフォント関連のクラスでタイプシステムを実装しています。Typography コンストラクタは各スタイルのデフォルトを提供するため、カスタマイズしないものは省略できます。

val Rubik = FontFamily(
    Font(R.font.rubik_regular),
    Font(R.font.rubik_medium, FontWeight.W500),
    Font(R.font.rubik_bold, FontWeight.Bold)
)

val MyTypography = Typography(
    h1 = TextStyle(
        fontFamily = Rubik,
        fontWeight = FontWeight.W300,
        fontSize = 96.sp
    ),
    body1 = TextStyle(
        fontFamily = Rubik,
        fontWeight = FontWeight.W600,
        fontSize = 16.sp
    )
    /*...*/
)
MaterialTheme(typography = MyTypography, /*...*/)

全体を通じて同じ書体を使用する場合は、defaultFontFamily parameter を指定し、TextStyle 要素の fontFamily を省略します。

val typography = Typography(defaultFontFamily = Rubik)
MaterialTheme(typography = typography, /*...*/)

テキスト スタイルの使用

TextStyle へのアクセスには MaterialTheme.typography が使用されます。次のように TextStyle を取得します。

Text(
    text = "Subtitle2 styled",
    style = MaterialTheme.typography.subtitle2
)

目的が異なるさまざまな書体の混在を示すスクリーンショット

図 8. 書体とスタイルを使い分けてブランドを表現します。

シェイプ

マテリアルはシェイプ システムを定義しており、大、中、小のコンポーネントのシェイプを定義できます。

さまざまなマテリアル デザイン シェイプを示しています

図 9. マテリアルのシェイプ システム。

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, /*...*/)

多くのコンポーネントで、こうしたシェイプがデフォルトで使用されます。たとえば、ButtonTextFieldFloatingActionButton のデフォルトは small、AlertDialog のデフォルトは medium、ModalDrawer のデフォルトは large です。マッピングの詳細については、シェイプ スキームのリファレンスをご覧ください。

シェイプの使用

Shape へのアクセスには MaterialTheme.shapes が使用されます。次のようなコードを使用して Shape を取得します。

Surface(
    shape = MaterialTheme.shapes.medium, /*...*/
) {
    /*...*/
}

マテリアル シェイプを使用して要素の状態を伝えるアプリのスクリーンショット

図 10. シェイプを使用してブランドや状態を表します。

デフォルト スタイル

Android View のデフォルト スタイルの Compose には、同等の概念はありません。マテリアル コンポーネントをラップする独自の「オーバーロード」したコンポーズ可能な関数を作成することで、同様の機能を実現できます。たとえば、ボタンのスタイルを作成するには、独自のコンポーズ可能な関数でボタンをラップし、変更するパラメータを直接設定します。他のパラメータは包含コンポーザブルにパラメータとして公開します。

@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
    )
}

テーマ オーバーレイ

MaterialTheme コンポーザブルをネストすることで、Android View のテーマ オーバーレイと同等の機能を Compose で実現できます。MaterialTheme では色、タイポグラフィ、シェイプが現在のテーマ値にデフォルトで設定されるため、テーマによってこれらのパラメータのうちの 1 つしか設定されていない場合、他のパラメータはデフォルト値を保持します。

さらに、View ベースの画面を Compose に移行する場合は、android:theme 属性の使い方に注意してください。Compose UI ツリーの該当部分に新しい MaterialTheme が必要になる場合があります。

Owl サンプルでは、詳細画面にはほとんどの画面で PinkTheme が使用され、関連するセクションには BlueTheme が使用されています。以下のスクリーンショットとコードをご覧ください。

図 11. Owl サンプルのネストされたテーマ。

@Composable
fun DetailsScreen(/* ... */) {
    PinkTheme {
        // other content
        RelatedSection()
    }
}

@Composable
fun RelatedSection(/* ... */) {
    BlueTheme {
        // content
    }
}

コンポーネントの状態

クリックや切り替えなど、操作可能なマテリアル コンポーネントには、さまざまな視覚状態が存在します。状態には「enabled」、「disabled」、「press」などがあります。

コンポーザブルには、多くの場合 enabled パラメータが含まれます。false に設定すると、操作ができなくなり、色やエレベーションなどのプロパティが変更され、コンポーネントの状態を視覚的に伝えることができます。

図 12. 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
    )
) { /* ... */ }

図 13. 色とエレベーションの値が調整された enabled = true(左)と enabled = false(右)を設定したボタン。

リップル

マテリアル コンポーネントでは、リップルを使用することで、自身が操作されていることを示すことができます。階層内で MaterialTheme を使用している場合、修飾子内(clickableindication など)で Ripple がデフォルトの Indication として使用されます。

ほとんどの場合、デフォルトの Ripple を使用できます。リップルの外観を構成するには、RippleTheme を使用して色やアルファなどのプロパティを変更します。

RippleTheme を拡張することで、defaultRippleColordefaultRippleAlpha ユーティリティ関数を使用できます。その後、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
  )
}

alt_text

図 14. RippleTheme で異なるリップル値を指定したボタン。

マテリアル デザイン 3 と Material You

Jetpack Compose には、マテリアル デザインの進化版であるマテリアル デザイン 3 の実装が用意されています。マテリアル 3 には、最新のテーマ設定とコンポーネント、ダイナミック カラーなどの Material You のパーソナライズ機能が含まれており、Android 12 の新しい視覚的スタイルおよびシステム UI と調和するように設計されています。

最初に、新しい Compose マテリアル 3 依存関係を build.gradle ファイルに追加します。

implementation "androidx.compose.material3:material3:material3_version"

M3 テーマにはカラーパターンタイポグラフィの値が含まれており、近日中にシェイプが更新されます。これらの値をカスタマイズすると、その変更は、アプリをビルドする際に使用する M3 コンポーネントに自動的に反映されます。

Jetpack Compose は、新しい M3 MaterialTheme コンポーザブルを使用して、これらのコンセプトを実装します。

MaterialTheme(
    colorScheme = …,
    typography = …
    // Updates to shapes coming soon
) {
    // M3 app content
}

アプリのテーマを設定するには、M3 MaterialTheme に渡すパラメータを構成します。

図 15. 最初の 2 つのスクリーンショットは、M3 MaterialTheme を構成していないため、デフォルトのスタイリングが使用されるアプリを示しています。次の 2 つのスクリーンショットは、スタイリングをカスタマイズするために MaterialTheme にパラメータを渡すアプリを示しています。

カラーパターン

マテリアル デザイン 3 では、カラーを「プライマリ」、「背景」、「エラー」などの名前付きカラースロットに分類します。これらはマテリアル 3 コンポーネントで使用されます。これらのスロットが組み合わされてカラーパターンが形成されます。各スロットで使用されるカラー値は、ユーザー補助要件を満たすように選択された色調パレットのセットから描画されます(たとえば、「プライマリ」スロットでは、「プライマリ上の」スロットでコントラストを付けることが保証されます)。カラーパターンには、ライトテーマとダークテーマの両方で、新しいデフォルトのベースライン カラーが用意されています。

図 16. ベースライン カラー値が指定されたマテリアル 3 の色調パレットとカラーパターン

Compose には、マテリアル 3 カラーパターンをモデル化するための ColorScheme クラスが用意されています。ColorScheme には、ライト カラーパターンまたはダーク カラーパターンを作成するためのビルダー関数が用意されています。

private val Blue40 = Color(0xff1e40ff​​)
private val DarkBlue40 = Color(0xff3e41f4)
private val Yellow40 = Color(0xff7d5700)
// Remaining colors from tonal palettes

private val LightColorScheme = lightColorScheme(
    primary = Blue40,
    secondary = DarkBlue40,
    tertiary = Yellow40,
    // error, primaryContainer, onSecondary, etc.
)
private val DarkColorScheme = darkColorScheme(
    primary = Blue80,
    secondary = DarkBlue80,
    tertiary = Yellow80,
    // error, primaryContainer, onSecondary, etc.
)

ColorScheme を定義したら、それを M3 MaterialTheme に渡すことができます。

val darkTheme = isSystemInDarkTheme()
MaterialTheme(
    colorScheme = if (darkTheme) DarkColorScheme else LightColorScheme
) {
    // M3 app content
}

カラーパターンの生成

カスタムの ColorScheme は手動で作成できますが、多くの場合、ブランドのソースカラーを使用して生成するほうが簡単です。マテリアル テーマビルダー ツールを使用すると、この処理を行い、必要に応じて Compose テーマ設定コードをエクスポートできます。

図 17. マテリアル テーマビルダー ツールで生成された、カスタムカラー値が指定されたマテリアル 3 の色調パレットとカラーパターン

動的なカラーパターン

ダイナミック カラーは Material You の重要な要素です。アルゴリズムはそれによってユーザーの壁紙からカスタムカラーを導出し、それらがアプリとシステム UI に適用されるようにします。このカラーパレットは、完全なライト カラーパターンとダーク カラーパターンを生成するための出発点として使用されます。

ダイナミック カラーは Android 12 以降で使用できます。ダイナミック カラーを使用できる場合は、動的な ColorScheme を設定できます。使用できない場合は、代替としてカスタムのライトまたはダーク ColorScheme を使用できます。

ColorScheme には、動的なライト カラーパターンまたはダーク カラーパターンを作成するためのビルダー関数が用意されています。

// Dynamic color is available on Android 12+
val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val colorScheme = when {
    dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current)
    dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
    darkTheme -> DarkColorScheme
    else -> LightColorScheme
}

図 18. 最初の 2 つのスクリーンショットは、赤い壁紙に基づく動的な ColorScheme を使用するアプリを示しています。次の 2 つのスクリーンショットは、青い壁紙に基づく動的な ColorScheme を使用するアプリを示しています。

カラーパターンの色の使用

MaterialTheme.colorScheme を使用すると、M3 MaterialTheme コンポーザブルに渡される ColorScheme を取得できます。

Text(
    text = "Hello M3 theming",
    color = MaterialTheme.colorScheme.tertiary
)

タイポグラフィ

マテリアル デザイン 3 では、マテリアル デザイン 2 から進化したテキスト スタイルなどのタイプスケールが定義されています。名前とグループ化は、表示、見出し、タイトル、本文、ラベルに簡略化され、それぞれに大、中、小のサイズがあります。

図 19. マテリアル 3 のタイプスケールとマテリアル 2 のタイプスケールの比較

Compose には、既存の TextStyle クラスおよびフォント関連のクラスとともに、マテリアル 3 タイプスケールをモデル化するための新しい M3 Typography クラスが用意されています。

val KarlaFontFamily = FontFamily(
    Font(R.font.karla_regular),
    Font(R.font.karla_bold, FontWeight.Bold)
)

val AppTypography = Typography(
    bodyLarge = TextStyle(
        fontFamily = KarlaFontFamily,
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp,
        lineHeight = 24.sp,
        letterSpacing = 0.15.sp
    ),
    // titleMedium, labelSmall, etc.
)

Typography を定義したら、それを M3 MaterialTheme に渡すことができます。

MaterialTheme(
    typography = AppTypography
) {
    // M3 app content
}

テキスト スタイルの使用

MaterialTheme.typography を使用すると、M3 MaterialTheme コンポーザブルに渡される Typography を取得できます。

Text(
    text = "Hello M3 theming",
    style = MaterialTheme.typography.bodyLarge
)

エレベーション

マテリアル 3 では、主に色調カラー オーバーレイを使用してエレベーションを表現します。これは、コンテナとサーフェスを区別する新しい方法です。色調エレベーションを高くすると、シャドウに加えて、より目立つ色調が使用されます。

ダークテーマのエレベーション オーバーレイも、マテリアル 3 の色調カラー オーバーレイに変更されました。

オーバーレイの色は、プライマリ カラースロットで指定されます。

図 20. ライトテーマとダークテーマにおけるマテリアル 3 のエレベーションとマテリアル 2 のエレベーションの比較

M3 Surface(ほとんどの M3 コンポーネントの背後にあるバッキング コンポーザブル)は、色調エレベーションとシャドウ エレベーションの両方をサポートします。

Surface(
    tonalElevation = 16.dp,
    shadowElevation = 16.dp
) {
    // Surface content
}

システム UI

Material You の一部の要素は、Android 12 の新しい視覚的スタイルとシステム UI に由来します。変更点がある 2 つの主要な領域は、リップルとオーバースクロールです。それらの変更を実装するための追加の作業は不要です。

リップル

リップルでは、タップされた際にサーフェスを明るくするために、かすかなスパークルが使用されるようになりました。Compose マテリアルのリップル内部的にプラットフォームの RippleDrawable を使用しているため、Android 12 以降ではすべてのマテリアル コンポーネントでスパークル リップルを使用できます。

図 21. Android 12 のリップルと Android 12 より前のリップルの比較

オーバースクロール

オーバースクロールでは、スクロール コンテナの端でストレッチ効果が使用されるようになりました。Compose Foundation 1.1.0 以降では、API レベルにかかわらず、スクロール コンテナのコンポーザブルでストレッチ オーバースクロールがデフォルトでオンになっています(LazyColumnLazyRowLazyVerticalGrid など)。

図 22. ストレッチ オーバースクロール

詳細

Compose のマテリアル テーマ設定の詳細については、以下の参考情報をご覧ください。

Codelab

動画