本記事は Android Advent Calendar 2021 の 6 日目の記事です。
Material 3 で TopAppBar のデザインや挙動が変わりました。
Jetpack Compose の Material3 対応版である androidx.compose.material3 を使用してガイドラインに合わせた実装例をいくつか見ていこうと思います。
※androidx.compose.material3 は 1.0.0-alpha02 時点の内容なので、ライブラリの更新で内容が変わる可能性もあります。
TopAppBar のパターン
Material 3 では TopAppBar に以下の 4 つのパターンがあります。
- Center-aligned
- Small
- Medium
- Large
それぞれの実装例を見ていきましょう。
Center-aligned
CenterAlignedTopAppBar の Composable 関数を使います。
@Composable
fun CenterAlignedTopAppBar(
    title: (@Composable () -> Unit)?,
    modifier: Modifier? = Modifier,
    navigationIcon: (@Composable () -> Unit)? = {},
    actions: (@Composable @ExtensionFunctionType RowScope.() -> Unit)? = {},
    colors: TopAppBarColors? = TopAppBarDefaults.centerAlignedTopAppBarColors(),
    scrollBehavior: TopAppBarScrollBehavior? = null
): Unit
CenterAlignedTopAppBar をそのまま使用した場合 Surface の色がそのまま適用されます。
Material 3 の TopAppBar はコンテンツのスクロールに合わせて elevation が変わる Lift On Scroll を適用する必要があり、Jetpack Compose では TopAppBarDefaults.pinnedScrollBehavior を使用して実装します。
@Composable
fun ExampleScreen() {
    val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() }
    Scaffold(
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
        topBar = {
            CenterAlignedTopAppBar(
                title = {
                    Text(text = "Title")
                },
                navigationIcon = {
                    BackIconButton {
                    }
                },
                scrollBehavior = scrollBehavior
            )
        }
    ) {
        LazyColumn(
            modifier = Modifier.fillMaxSize(),
            contentPadding = it
        ) {
            ...
        }
    }
}
 
 
Small
SmallTopAppBar の Composable 関数を使います。
@Composable
fun SmallTopAppBar(
    title: (@Composable () -> Unit)?,
    modifier: Modifier? = Modifier,
    navigationIcon: (@Composable () -> Unit)? = {},
    actions: (@Composable @ExtensionFunctionType RowScope.() -> Unit)? = {},
    colors: TopAppBarColors? = TopAppBarDefaults.smallTopAppBarColors(),
    scrollBehavior: TopAppBarScrollBehavior? = null
): Unit
CenterAlignedTopAppBar と同じく、スクロールに合わせて TopAppBar の色を変えるには TopAppBarDefaults.pinnedScrollBehavior を使用して以下のように実装する必要があります。
@Composable
fun ExampleScreen() {
    val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() }
    Scaffold(
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
        topBar = {
            SmallTopAppBar(
                title = {
                    Text(text = "Title")
                },
                navigationIcon = {
                    BackIconButton {
                    }
                },
                scrollBehavior = scrollBehavior
            )
        }
    ) {
        LazyColumn(
            modifier = Modifier.fillMaxSize(),
            contentPadding = it
        ) {
            ...
        }
    }
}
また、TopAppBarDefaults.enterAlwaysScrollBehavior を使うと上にスクロールすると TopAppBar を隠し下にスクロールさせると TopAppBar を表示させる挙動にすることもできます。
 
 
Medium
MediumTopAppBar の Composable 関数を使います。
@Composable
fun MediumTopAppBar(
    title: (@Composable () -> Unit)?,
    modifier: Modifier? = Modifier,
    navigationIcon: (@Composable () -> Unit)? = {},
    actions: (@Composable @ExtensionFunctionType RowScope.() -> Unit)? = {},
    colors: TopAppBarColors? = TopAppBarDefaults.mediumTopAppBarColors(),
    scrollBehavior: TopAppBarScrollBehavior? = null
): Unit
Medium の TopAppBar は上にスクロールすると折り畳まれる必要があります。
また Medium の TopAppBar はスクロールが一番上に到達するまで折り畳まれている必要があるので、TopAppBarDefaults.enterAlwaysScrollBehavior ではなく TopAppBarDefaults.exitUntilCollapsedScrollBehavior を使用することで一番上にスクロールするまで折り畳まれた状態にすることができます。
@Composable
fun ExampleScreen() {
    val decayAnimationSpec = rememberSplineBasedDecay<Float>()
    val scrollBehavior = remember(decayAnimationSpec) {
        TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec)
    }
    Scaffold(
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
        topBar = {
            MediumTopAppBar(
                title = {
                    Text(text = "Title")
                },
                navigationIcon = {
                    BackIconButton {
                    }
                },
                scrollBehavior = scrollBehavior
            )
        }
    ) {
        LazyColumn(
            modifier = Modifier.fillMaxSize(),
            contentPadding = it
        ) {
            ...
        }
    }
}
 
 
Large
LargeTopAppBar の Composable 関数を使います。
@Composable
fun LargeTopAppBar(
    title: (@Composable () -> Unit)?,
    modifier: Modifier? = Modifier,
    navigationIcon: (@Composable () -> Unit)? = {},
    actions: (@Composable @ExtensionFunctionType RowScope.() -> Unit)? = {},
    colors: TopAppBarColors? = TopAppBarDefaults.largeTopAppBarColors(),
    scrollBehavior: TopAppBarScrollBehavior? = null
): Unit
Medium と同じくスクロールした時に折り畳まれているようにするため TopAppBarDefaults.exitUntilCollapsedScrollBehavior を実装します。
@Composable
fun ExampleScreen() {
    val decayAnimationSpec = rememberSplineBasedDecay<Float>()
    val scrollBehavior = remember(decayAnimationSpec) {
        TopAppBarDefaults.exitUntilCollapsedScrollBehavior(decayAnimationSpec)
    }
    Scaffold(
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
        topBar = {
            LargeTopAppBar(
                title = {
                    Text(text = "Title")
                },
                navigationIcon = {
                    BackIconButton {
                    }
                },
                scrollBehavior = scrollBehavior
            )
        }
    ) {
        LazyColumn(
            modifier = Modifier.fillMaxSize(),
            contentPadding = it
        ) {
            ...
        }
    }
}
 
 
Material 3 では TopAppBar にいくつか種類が登場し、Jetpack Compose では Lift On Scroll のために少しばかり実装の必要があります。




