Material3のTopAppBarは、コンテンツのスクロールに合わせて色が変化します。今回はこれの実現方法を紹介します。さらに、StatusBarの色もTopAppBarに合わせて変化させる方法も説明します。
やりたいこと
Material3のTopAppBar(画面のタイトルなどが表示される部分。従来はToolBarやActionBarとも呼ばれていた。)は、コンテンツのスクロールに合わせて色を変化させるとガイドラインに定められています。一方でStatusBar(通知や時計などが表示される部分)の色はガイドラインには明記されていませんが、GmailなどのGoogle製アプリやAndroid標準の設定アプリなどでは、TopAppBarの色に合わせてStatusBarの色も変化しています。今回はこれを、TopAppBarScrollBehavior
とAccompanistのSystem UI Controllerを使って実現します。
環境
- Kotlin 1.6.10
- Jetpack Compose 1.1.1
- Material3 1.0.0 alpha8
- Accompanist 0.23.1
Jetpack Compose周辺は日々変化していますので、最新の情報を参照して下さい。
ソースコードと結果
依存関係の追加
dependencies {
implementation 'androidx.compose.material3:material3:1.0.0-alpha08'
implementation 'com.google.accompanist:accompanist-systemuicontroller:0.23.1'
}
コンポーザブル
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppScreen() {
val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() }
val statusBarColor = TopAppBarDefaults.centerAlignedTopAppBarColors()
.containerColor(scrollFraction = scrollBehavior.scrollFraction).value
val systemUiController = rememberSystemUiController()
SideEffect {
systemUiController.setStatusBarColor(statusBarColor)
}
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
CenterAlignedTopAppBar(
title = { Text("TopAppBar") },
scrollBehavior = scrollBehavior
)
}
) {
LazyColumn {
items(100) { count ->
Text(
text = "Item ${count + 1}",
modifier = Modifier.fillMaxWidth().height(30.dp).padding(20.dp, 4.dp)
)
}
}
}
}
結果
説明
依存関係の追加
dependencies {
implementation 'androidx.compose.material3:material3:1.0.0-alpha08'
implementation 'com.google.accompanist:accompanist-systemuicontroller:0.23.1'
}
Material3に移行していることが前提になります。build.gradle
のdependencies
には、material3
ライブラリを追加します。Material3への移行について、詳しくは「Jetpack ComposeアプリをMaterial Design 3へ移行する」を参照してください。
また、AccompanistのSystem UI Controllerを使います。accompanist-systemuicontroller
を追加しておきます。System UI Controllerを使ってStatus Barの色を変化させる方法は、「Jetpack ComposeでStatus Barの色を変更したい」にも詳しく書いていますので、そちらも参考にしてください。
TopAppBarの色の変化
val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() }
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
CenterAlignedTopAppBar(
title = { Text("TopAppBar") },
scrollBehavior = scrollBehavior
)
}
) {
LazyColumn {
...
}
}
スクロールに合わせてTopAppBarの色を変化させるには、androidx.compose.material3
パッケージのTopAppBarScrollBehavior
を使います。
TopAppBarScrollBehavior
には、コンテンツをスクロールした時のTopAppBarの振る舞いが定義されていて、TopAppBarDefaults
に3種類(pinnedScrollBehavior
, enterAlwaysScrollBehavior
, exitUntilCollapsedScrollBehavior
)が定義されています。最も基本的なpinnedScrollBehavior
は、TopAppBarの位置やサイズは固定で、色のみ変化させます。
scrollBehavior
をremember
で定義しているのは、このあとStatus Barの色を設定するために必要になるからです。TopAppBarの色だけであれば、remember
ではなく普通の変数として定義しても問題ないです。
TopAppBar
とスクロールコンテンツ(上の例ではLazyColumn
)は、Scaffold
を使ってレイアウトします。作成したscrollBehavior
オブジェクトをScaffold
内のTopAppBar
のscrollBehavior
にセットし、Scaffold
自体のmodifier
にscrollBehavior.nestedScrollConnection
を渡すことによって、コンテンツのスクロール状態とTopAppBarの状態が同期します。
StatusBarの色の変化
val scrollBehavior = remember { TopAppBarDefaults.pinnedScrollBehavior() }
val statusBarColor = TopAppBarDefaults.centerAlignedTopAppBarColors()
.containerColor(scrollFraction = scrollBehavior.scrollFraction).value
val systemUiController = rememberSystemUiController()
SideEffect {
systemUiController.setStatusBarColor(statusBarColor)
}
StatusBarの色は、AccompanistのSystem UI Controllerを使って設定します。先ほど作成したscrollBehavior
オブジェクトを使って、TopAppBarの現在の色を取得し、setStatusBarColor()
に渡します。
TopAppBar
の色は、TopAppBarDefaults
から取得します。この時、scrollFraction
にscrollBehavior
オブジェクトのscrollFraction
を渡すことによって、現在のスクロール状態に合わせた色を取得できます。
コンテンツは随時追加していきます。