🐻‍❄️

[Jetpack Compose]無限ループするViewPagerを作成する

2023/05/09に公開

実装方法

ViewPagerのページ数をInt最大値に設定して、0〜Int最大値の範囲に特定のデータを繰り返し表示して、無限ループするViewPagerを作成する。

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun LoopViewPager() {
    // 表示する3つのテキストデータ
    val texts = listOf("ONE", "TWO", "THREE")
    val textCount = texts.count()

    // ページカウントをInt最大値にして、実質無限回スワイプできるようにする
    val dummyPageCount = Int.MAX_VALUE

    // 左右にスワイプしてすぐに先頭・最後尾に到達しないように初期ページ位置を全てのページの真ん中の位置に設定する
    val pagerState = rememberPagerState(
        initialPage = (dummyPageCount / textCount / 2) * textCount
    )

    Column(
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        // Int最大値の要素を表示するViewPager
        HorizontalPager(pageCount = dummyPageCount, state = pagerState) { dummyIndex ->
            // 実際に表示するテキストデータは3つなので、それぞれの場所に繰り返し3つのテキストデータが表示されるようにする
            val text = texts[dummyIndex % textCount]
            Card(modifier = Modifier.size(256.dp)) {
                Box(modifier = Modifier.fillMaxSize()) {
                    Text(
                        text = text,
                        fontSize = 32.sp,
                        modifier = Modifier.align(Alignment.Center)
                    )
                }
            }
        }

        // ViewPagerで表示されているテキストデータの位置を表すインジケータ
        Row(
            horizontalArrangement = Arrangement.spacedBy(16.dp),
            modifier = Modifier.align(Alignment.CenterHorizontally)
        ) {
            repeat(textCount) { index ->
                // PagerStateには0〜Int最大値の値が入ってくる
                val currentDummyIndex = pagerState.currentPage

                // 0〜Int最大値の範囲で3つのデータが繰り返し表示されている。
                // 繰り返し表示されている3つのデータのうちどれが表示されているか算出する
                val currentIndex = currentDummyIndex % textCount

                // データの表示状況に応じて、インジケータの色を変更する
                val color = if (currentIndex == index) Color.Red else Color.LightGray
                Box(
                    modifier = Modifier
                        .background(shape = CircleShape, color = color)
                        .size(16.dp)
                )
            }
        }
    }
}

Discussion