DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Pager完全ガイド — HorizontalPager/VerticalPager/インジケーター/変換

この記事で学べること

Pager(HorizontalPager、VerticalPager、ページインジケーター、ページ変換エフェクト)を解説します。


HorizontalPager

@Composable
fun OnboardingPager() {
    val pages = listOf(
        "ようこそ" to "アプリの紹介",
        "機能" to "便利な機能を紹介",
        "始めましょう" to "さっそく使ってみよう"
    )
    val pagerState = rememberPagerState(pageCount = { pages.size })

    Column(Modifier.fillMaxSize()) {
        HorizontalPager(
            state = pagerState,
            modifier = Modifier.weight(1f)
        ) { page ->
            Column(
                Modifier.fillMaxSize().padding(32.dp),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(pages[page].first, style = MaterialTheme.typography.headlineLarge)
                Spacer(Modifier.height(16.dp))
                Text(pages[page].second, style = MaterialTheme.typography.bodyLarge)
            }
        }

        // ドットインジケーター
        Row(
            Modifier.fillMaxWidth().padding(16.dp),
            horizontalArrangement = Arrangement.Center
        ) {
            repeat(pages.size) { index ->
                Box(
                    Modifier
                        .padding(4.dp)
                        .size(if (pagerState.currentPage == index) 12.dp else 8.dp)
                        .clip(CircleShape)
                        .background(
                            if (pagerState.currentPage == index)
                                MaterialTheme.colorScheme.primary
                            else MaterialTheme.colorScheme.outline
                        )
                )
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

VerticalPager

@Composable
fun VerticalCardPager(items: List<CardItem>) {
    val pagerState = rememberPagerState(pageCount = { items.size })

    VerticalPager(
        state = pagerState,
        modifier = Modifier.fillMaxSize(),
        pageSpacing = 16.dp,
        contentPadding = PaddingValues(vertical = 32.dp)
    ) { page ->
        Card(
            Modifier
                .fillMaxWidth()
                .padding(horizontal = 16.dp)
                .graphicsLayer {
                    val pageOffset = (pagerState.currentPage - page) +
                        pagerState.currentPageOffsetFraction
                    alpha = lerp(0.5f, 1f, 1f - pageOffset.absoluteValue.coerceIn(0f, 1f))
                    scaleX = lerp(0.85f, 1f, 1f - pageOffset.absoluteValue.coerceIn(0f, 1f))
                    scaleY = lerp(0.85f, 1f, 1f - pageOffset.absoluteValue.coerceIn(0f, 1f))
                }
        ) {
            Column(Modifier.padding(24.dp)) {
                Text(items[page].title, style = MaterialTheme.typography.headlineSmall)
                Spacer(Modifier.height(8.dp))
                Text(items[page].description)
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

ページ変更検知

@Composable
fun PagerWithCallback() {
    val pagerState = rememberPagerState(pageCount = { 5 })

    LaunchedEffect(pagerState) {
        snapshotFlow { pagerState.currentPage }.collect { page ->
            // ページ変更時の処理(Analytics等)
            Log.d("Pager", "Current page: $page")
        }
    }

    HorizontalPager(state = pagerState) { page ->
        Text("Page $page", Modifier.fillMaxSize().padding(16.dp))
    }
}
Enter fullscreen mode Exit fullscreen mode

まとめ

API 用途
HorizontalPager 横スワイプページ
VerticalPager 縦スワイプページ
PagerState ページ状態管理
currentPageOffsetFraction ページ変換エフェクト
  • HorizontalPagerでオンボーディング/画像ギャラリー
  • VerticalPagerでTikTok風縦スクロール
  • graphicsLayerでスケール/フェードエフェクト
  • snapshotFlowでページ変更を検知

8種類のAndroidアプリテンプレート(Pager対応)を公開しています。

テンプレート一覧Gumroad

関連記事:


I publish 8 Android app templates on Gumroad.

Browse templatesGumroad

Top comments (0)