Jetpack Compose の Pager を使って自動で動くカルーセルを実装するときの例になります。
(Jetpack Compose BOM 2022.12.00 & Accompanist v0.28.0 での実装です)
実装例
@Composable
fun rememberAutoScrollPagerState(
interval: Long,
initialPage: Int = 0,
): PagerState {
val lifecycleOwner = LocalLifecycleOwner.current
val pagerState = rememberPagerState(initialPage = initialPage)
var refreshCount by remember { mutableStateOf(0) }
val isScrolling = pagerState.isScrollInProgress
LaunchedEffect(refreshCount) { // ③
runCatching {
val target = pagerState.currentPage + 1
pagerState.animateScrollToPage(
if (target >= pagerState.pageCount) {
0
} else {
target
}
)
}
}
LaunchedEffect(isScrolling) { // ①
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
if (!isScrolling) {
delay(interval)
refreshCount++ // ②
}
}
}
return pagerState
}
このような Composable 関数を用意しておき、あとは Pager を実装する時に組み込むだけです。
@Composable
fun CarouselBanners(
modifier: Modifier = Modifier,
) {
// Line this
val state = rememberAutoScrollPagerState(
interval = 2000,
)
HorizontalPager(
count = 10,
state = state,
modifier = modifier,
) { index ->
Item(...)
}
}
解説
① の LaunchedEffect
でスワイプによる移動やコードからのページ送りがされたタイミングで処理が呼ばれるようにして、② でページ送りがされてスクロールが停止したタイミングでページ送りの処理をトリガーさせます。
トリガーされたページ送りの処理を ③ の LaunchedEffect
が処理して実際にページを移動させます。
LaunchedEffect
を 1 つだけで制御しようとすると LaunchedEffect
に渡す key が変わると内部の処理がキャンセルされる挙動のおかげで animateScrollToPage
が途中でキャンセルされたりするため、スクロールの処理とページ移動のトリガーを分離する必要があります。
LaunchedEffect
はシンプルが故に少しのパズルが必要になる場合がありますが、 駆使することでこのような自動で動くカルーセルも簡単に実装できます。