2024年10月23日水曜日

AutoScrollHorizontalPager を作る

  • (擬似的に)無限ループしたい
  • タップされているときは自動送りしない
private const val PAGE_COUNT = 10_000 private const val INITIAL_PAGE = PAGE_COUNT / 2 private fun Int.floorMod(other: Int): Int = when (other) { 0 -> this else -> this - this.floorDiv(other) * other } @Composable fun AutoScrollHorizontalPager( itemSize: Int, modifier: Modifier = Modifier, autoScrollDuration: Long = 2_000L, onPageChanged: ((page: Int) -> Unit)? = null, pageContent: @Composable PagerScope.(page: Int) -> Unit, ) { val pagerState = rememberPagerState(INITIAL_PAGE) { PAGE_COUNT } fun Int.toIndex(): Int = (this - INITIAL_PAGE).floorMod(itemSize) if (onPageChanged != null) { LaunchedEffect(onPageChanged) { snapshotFlow { pagerState.currentPage } .collect { page -> onPageChanged(page.toIndex()) } } } val dragged by pagerState.interactionSource.collectIsDraggedAsState() if (!dragged) { LaunchedEffect(Unit) { while (true) { delay(autoScrollDuration) val nextPage = pagerState.currentPage + 1 if (nextPage < PAGE_COUNT) { pagerState.animateScrollToPage(nextPage) } else { pagerState.scrollToPage(0) } } } } HorizontalPager( state = pagerState, modifier = modifier, ) { page -> pageContent(page.toIndex()) } }