先日投稿した、Material 3で大きく変わったTopAppBarをJetpack Composeで実装してみる の補足記事になります。
前回の記事で紹介した androidx.compose.material3 の TopAppBar ですが、そのまま実装すると StatusBar の下まで表示させる Edge to edge の対応ができません。
androidx.compose.material の方は Accompanist の Inset がその辺りの実装をライブラリとして提供してくれていますが、androidx.compose.material3 の方は存在しない ( issue は立っている) ので実装が必要になります。
Accompanist で提供されそうな予感もしつつ、対応するための実装を書いていこうと思います。
(Accompanist の Inset 周りのコードの説明は省略します。)
TopAppBar に padding を設定しても背景色は適用されない
以下のコードのように TopAppBar に StatusBar の高さ分の padding を設定すると StatusBar の部分に空白ができるて背景色が反映されない状態になります。
Jetpack Compose の modifier の挙動ではあるものの、StatusBar の下まで TopAppBar の背景色を表示させたいのでこれだと対応が不十分です。
@Composable
fun ExampleScreen() {
    val statusBarPadding = rememberInsetsPaddingValues(
        LocalWindowInsets.current.statusBars,
        applyBottom = false,
    )
    val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() }
    Scaffold(
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
        topBar = {
            SmallTopAppBar(
                title = {
                    Text(text = "Title")
                },
                navigationIcon = {
                    BackIconButton {
                    }
                },
                scrollBehavior = scrollBehavior,
                modifier = Modifier.padding(statusBarPadding),
            )
        }
    ) {
        // contents
    }
}
 
実装
以下のようなコードで TopAppBar に padding を適用しても背景色が適用されるようにします
- TopAppBar の背景色は透明にする
- 
Surface側で本来 TopAppBar で表示されるはずの背景色をセットする
- 外から padding を設定できるようにして TopAppBar 側にセットする
(SmallTopAppBar のコードになりますが、Medium や Large も同じ要領で実装できます。)
@Composable
fun SmallTopAppBar(
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues = PaddingValues(0.dp),
    navigationIcon: @Composable () -> Unit = {},
    actions: @Composable RowScope.() -> Unit = {},
    colors: TopAppBarColors = TopAppBarDefaults.smallTopAppBarColors(),
    scrollBehavior: TopAppBarScrollBehavior? = null,
) {
    val backgroundColor = colors.containerColor(
        scrollFraction = scrollBehavior?.scrollFraction ?: 0.0f
    ).value
    Surface(
        color = backgroundColor,
        modifier = modifier,
    ) {
        androidx.compose.material3.SmallTopAppBar(
            title = title,
            navigationIcon = navigationIcon,
            actions = actions,
            scrollBehavior = scrollBehavior,
            colors = TopAppBarDefaults.smallTopAppBarColors(
                containerColor = Color.Transparent,
                scrolledContainerColor = Color.Transparent
            ),
            modifier = Modifier.padding(contentPadding),
        )
    }
}
ここで実装した TopAppBar を使うことで StatusBar の下まで TopAppBar を正しく表示させることができます。
@Composable
fun ExampleScreen() {
    val statusBarPadding = rememberInsetsPaddingValues(
        LocalWindowInsets.current.statusBars,
        applyBottom = false,
    )
    val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() }
    Scaffold(
        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
        topBar = {
            SmallTopAppBar(
                title = {
                    Text(text = "Title")
                },
                navigationIcon = {
                    BackIconButton {
                    }
                },
                scrollBehavior = scrollBehavior,
                contentPadding = statusBarPadding,
            )
        }
    ) {
        // contents
    }
}
 
