28
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Material 3で大きく変わったTopAppBarをJetpack Composeで実装してみる

Last updated at Posted at 2021-12-05

本記事は 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

Center-aligned top app bar image

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

Small top app bar image

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

Medium top app bar image

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

Large top app bar image

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 のために少しばかり実装の必要があります。

参考

28
15
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?