Jetpack ComposeでMaterial3のTopAppBarをStatusBarの下まで表示させる

先日投稿した、[Material 3で大きく変わったTopAppBarをJetpack Composeで実装してみる](https://qiita.com/Nabe1216/items/0823dc7ebfb5d616f9c1　) の補足記事になります。


前回の記事で紹介した `androidx.compose.material3` の TopAppBar ですが、そのまま実装すると StatusBar の下まで表示させる Edge to edge の対応ができません。

`androidx.compose.material` の方は Accompanist の [Inset](https://google.github.io/accompanist/insets/) がその辺りの実装をライブラリとして提供してくれていますが、`androidx.compose.material3` の方は存在しない ( [issue](https://github.com/google/accompanist/issues/836) は立っている) ので実装が必要になります。

Accompanist で提供されそうな予感もしつつ、対応するための実装を書いていこうと思います。
(Accompanist の Inset 周りのコードの説明は省略します。)

## TopAppBar に padding を設定しても背景色は適用されない

以下のコードのように TopAppBar に StatusBar の高さ分の padding を設定すると StatusBar の部分に空白ができるて背景色が反映されない状態になります。
Jetpack Compose の modifier の挙動ではあるものの、StatusBar の下まで TopAppBar の背景色を表示させたいのでこれだと対応が不十分です。

```kotlin
@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
    }
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/fbb4fca5-6a29-28d9-86f9-bd964fd106e5.png" width="200px" />

## 実装

以下のようなコードで TopAppBar に padding を適用しても背景色が適用されるようにします

- TopAppBar の背景色は透明にする
- `Surface` 側で本来 TopAppBar で表示されるはずの背景色をセットする
- 外から padding を設定できるようにして TopAppBar 側にセットする

(`SmallTopAppBar` のコードになりますが、Medium や Large も同じ要領で実装できます。)

```kotlin
@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 を正しく表示させることができます。

```kotlin
@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
    }
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/432fc055-b595-3147-ad86-44077aaecdb0.png" width="200px" />