どちらかというとオーバースクロールエフェクトはAndroid 12より前のほうがどこが端なのかが分かりやすくなっています。
※ここから先は見た目がわかりやすいAndroid 12より前で挙動を確認していきます。
Column/RowのModifierの順番
Column
でスクロールするときは以下のような感じの実装になると思います。
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
) {
(1..30).forEach { /* */ }
}
これに全体のPaddingを設定する際に Modifier
の順番に注意する必要があります。
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp) // verticalScroll の前に padding を設定
.verticalScroll(rememberScrollState())
) {
// ...
}
verticalScroll
の前に padding
を設定すると、以下のようになります。
見てもらえれば分かるようにPaddingの中にオーバースクロールエフェクトが表示されてしまいます。ちょっとイマイチな感じになっちゃってます。
Paddingを設定してからのScrollという感じの設定になっているので、順番を変えてあげます。
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.padding(16.dp) // verticalScroll の後に padding を設定
) {
// ...
}
これを実行すると以下のように全体にオーバースクロールエフェクトが表示されるようになります。
LazyColumn/LazyRowのPadding
LazyColumn
の場合も先程と同じように注意しないとPaddingの中にオーバースクロールエフェクトが表示されることになります。
// NG
LazyColumn(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.padding(16.dp)
) {
// ...
}
LazyColumn
では Modifier.padding
を使うとPaddingの中にオーバースクロールエフェクトが表示されてしまいます。
LazyColumn
の場合は contentPadding
で設定すると全体にオーバースクロールエフェクトが表示されるようになります。
// OK
LazyColumn(
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(16.dp)
) {
// ...
}
Edge-to-edgeの対応
設定アプリのオーバースクロールエフェクトを確認すると、以下のようにOSのナビゲーションの上にエフェクトが表示されてるのが分かると思います。
Edge-to-edgeが有効にしてComposeで下にInsetのスペースを入れた実装してみます。
enableEdgeToEdge() // Activity側でEdge-to-edgeを有効にする
LazyColumn(
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(16.dp)
) {
// ...
// https://developer.android.com/jetpack/compose/layouts/insets#inset-size
item {
Spacer(
Modifier.windowInsetsBottomHeight(
WindowInsets.systemBars
)
)
}
}
これを実行すると、以下のようになります。
ちょっと分かりにくいかもですが、オーバースクロールエフェクトがOSナビゲーションバーの下に表示されてしまっています。
これに対応するには、 OverscrollConfiguration
を使ってオーバースクロールエフェクトをカスタマイズしていきます。
カスタマイズするには、 CompositionLocal
を使っていきます。
CompositionLocalProvider(
// 下位階層のオーバースクロールエフェクトをカスタマイズ
LocalOverscrollConfiguration provides OverscrollConfiguration(
// OSナビゲーションバーのPaddingを設定する
drawPadding = WindowInsets.systemBars.only(
WindowInsetsSides.Bottom
).asPaddingValues()
)
) {
LazyColumn {}
}
これを実行すると、OSナビゲーションバーの上にオーバースクロールエフェクトが表示されるようになります。
実はこれでは完璧ではないケースがあります。他にもIMEが表示されてる場合も色々考える必要がありますので、 WindowInsets.ime
も組み合わせていく必要もあります。
説明は省略しますが、IMEも対応する場合は以下のような感じの実装になります。
CompositionLocalProvider(
LocalOverscrollConfiguration provides OverscrollConfiguration(
drawPadding = WindowInsets.safeDrawing
.exclude(WindowInsets.ime)
.only(
WindowInsetsSides.Bottom
).asPaddingValues()
)
) {
LazyColumn {}
}
このあたりは WindowInsets
についての知識が必要になってきます。