Kotlin Jetpack Composeでページネーション付きのレイアウト

Kotlin Kotlin
Kotlin

Jetpack Composeを使用して、ページネーション付きの横にスワイプ可能なページングレイアウトを作成した際のメモ。

個人的にJetpack Composeは非常にレイアウトし易いと思います。
逆にXMLのレイアウトってイメージし難いんですよね・・・

ソースコード

左右にスワイプしてページを切り替える事ができるレイアウトです。
ページネーションの丸をタップすると、該当ページにスクロール。
ページネーションの左右のスペースをタップすると、左右にスクロールするようにしてあります。

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TestPagingScreen() {
    // 表示するデータ
    val list = listOf<String>("aaa", "bbb", "ccc", "ddd", "eee", "fff",)

    // HorizontalPagerの状態
    val pagingState = rememberPagerState()
    // CoroutinScope scrollToPageを実行するのに必要
    val scope = rememberCoroutineScope()

    val text = remember {
        mutableStateOf("")
    }
    val position = remember {
        mutableStateOf(0)
    }

    Box(
        modifier = Modifier
    ) {
        HorizontalPager(
            pageCount = list.size,
            state = pagingState,
            modifier = Modifier.fillMaxSize()
        ) { page ->

            Column(
                modifier = Modifier.fillMaxSize()
            ) {
                Text(text = "${list[page]} $page page")
            }

        }

        Text(
            text = text.value,
            modifier = Modifier.align(Alignment.Center)
        )

        Row(
            horizontalArrangement = Arrangement.Center,
            modifier = Modifier
                .fillMaxWidth()
                .align(Alignment.BottomCenter)
                .pointerInput(Unit) {
                    detectTapGestures {
                        val tapPositionX = it.x
                        // サイズを取得
                        val widthSize = this.size.width

                        if (tapPositionX < (widthSize / 2)) {
                            text.value = "left $tapPositionX"
                            scope.launch {
                                pagingState.scrollToPage(pagingState.currentPage - 1)
                            }
                        } else {
                            text.value = "right $tapPositionX"
                            scope.launch {
                                pagingState.scrollToPage(pagingState.currentPage + 1)
                            }
                        }
                    }
                }
        ) {
            Row(
                modifier = Modifier
            ) {
                repeat(list.size) { iterator ->
                    val color = if (pagingState.currentPage == iterator) Color.Gray else Color.LightGray
                    Box(
                        modifier = Modifier
                            .padding(4.dp)
                            .clip(CircleShape)
                            .background(color)
                            .size(16.dp)
                            .clickable {
                                text.value = "box tap $iterator"
                                scope.launch {
                                    pagingState.scrollToPage(iterator)
                                }
                            }

                    )
                }
            }

        }
    }
}

これだけで、ページング付きのレイアウトが作成できます。

悩んだのは、ページネーションの左右のスペースをタップした際に、スクロールさせるために、タップ位置を判定するための処理を簡単に書く方法を調べる事でした。

pointerInput内でthis.sizeで大きさを取得できる事が分かって、非常に簡単に記述する事ができました。

コメント

タイトルとURLをコピーしました