コンテンツを水平方向または垂直方向にフリップするには、
HorizontalPager コンポーザブルと VerticalPager コンポーザブルを使用します。これらは、ビュー システムの ViewPager
と同様の機能を備えています。デフォルトでは、HorizontalPager は画面の幅全体を使用し、VerticalPager
は画面の高さ全体を使用します。また、ページャーは一度に 1
ページしかフリングしません。これらのデフォルトはすべて構成可能です。
HorizontalPager
左右に水平スクロールするページャーを作成するには、HorizontalPager を使用します。
HorizontalPager
// Display 10 items val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier.fillMaxWidth() ) }
VerticalPager
上下にスクロールするページャーを作成するには、VerticalPager を使用します。
VerticalPager
// Display 10 items val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier.fillMaxWidth() ) }
遅延作成
HorizontalPager と VerticalPager の両方のページは、必要に応じて遅延コンポーズされ
、レイアウトされます。ユーザーがページをスクロールすると、コンポーザブルは不要になったページを削除します。
画面外のページをさらに読み込む
デフォルトでは、ページャーは画面に表示されているページのみを読み込みます。画面外のページをさらに読み込むには、beyondBoundsPageCount を 0 より大きい値に設定します。
ページャー内の項目にスクロールする
ページャー内の特定のページにスクロールするには、PagerState オブジェクト
を rememberPagerState() を使用して作成し、ページャーに state パラメータとして渡します。`
CoroutineScope` 内で、この状態に対して
`PagerState#scrollToPage()` を呼び出すことができます。
val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier .fillMaxWidth() .height(100.dp) ) } // scroll to page val coroutineScope = rememberCoroutineScope() Button(onClick = { coroutineScope.launch { // Call scroll to on pagerState pagerState.scrollToPage(5) } }, modifier = Modifier.align(Alignment.BottomCenter)) { Text("Jump to Page 5") }
ページにアニメーションを表示する場合は、
PagerState#animateScrollToPage() 関数を使用します。
val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier .fillMaxWidth() .height(100.dp) ) } // scroll to page val coroutineScope = rememberCoroutineScope() Button(onClick = { coroutineScope.launch { // Call scroll to on pagerState pagerState.animateScrollToPage(5) } }, modifier = Modifier.align(Alignment.BottomCenter)) { Text("Jump to Page 5") }
ページの状態の変化に関する通知を受け取る
PagerState には、ページに関する情報を含む 3 つのプロパティ(
currentPage、settledPage、targetPage)があります。
currentPage: スナップ位置に最も近いページ。デフォルトでは、スナップ位置はレイアウトの先頭にあります。settledPage: アニメーションやスクロールが実行されていないときのページ番号。ページがスナップ位置に十分に近い場合、currentPageはすぐに更新されますが、settledPageはすべてのアニメーションが完了するまで同じままです。この点がcurrentPageプロパティとは異なります。targetPage: スクロール移動の停止位置の候補。
snapshotFlow 関数を使用すると、これらの変数の変更を監視して対応できます。たとえば、ページが切り替わるたびに分析イベントを送信するには、次のようにします。
val pagerState = rememberPagerState(pageCount = { 10 }) LaunchedEffect(pagerState) { // Collect from the a snapshotFlow reading the currentPage snapshotFlow { pagerState.currentPage }.collect { page -> // Do something with each page change, for example: // viewModel.sendPageSelectedEvent(page) Log.d("Page change", "Page changed to $page") } } VerticalPager( state = pagerState, ) { page -> Text(text = "Page: $page") }
ページ インジケーターを追加する
ページにインジケーターを追加するには、PagerState
オブジェクトを使用して、複数のページの中から選択されているページに関する情報を取得し、カスタム インジケーターを描画します。
たとえば、円形のインジケーターを作成するには、pagerState.currentPage を使用して円の数を繰り返し、ページが選択されているかどうかに基づいて円の色を変更します。
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, modifier = Modifier.fillMaxSize() ) { page -> // Our page content Text( text = "Page: $page", ) } Row( Modifier .wrapContentHeight() .fillMaxWidth() .align(Alignment.BottomCenter) .padding(bottom = 8.dp), horizontalArrangement = Arrangement.Center ) { repeat(pagerState.pageCount) { iteration -> val color = if (pagerState.currentPage == iteration) Color.DarkGray else Color.LightGray Box( modifier = Modifier .padding(2.dp) .clip(CircleShape) .background(color) .size(16.dp) ) } }
コンテンツに項目スクロール効果を適用する
一般的なユースケースは、スクロール位置を使用してページャー項目に効果を適用することです。ページが選択したページからどのくらい離れているかを確認するには、
PagerState.currentPageOffsetFractionを使用します。選択したページからの距離に基づいて、コンテンツに変換効果を適用できます。
たとえば、中央からの距離に基づいて項目の不透明度を調整するには、ページャー内の項目で Modifier.graphicsLayer を使用して alpha を変更します。
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager(state = pagerState) { page -> Card( Modifier .size(200.dp) .graphicsLayer { // Calculate the absolute offset for the current page from the // scroll position. We use the absolute value which allows us to mirror // any effects for both directions val pageOffset = ( (pagerState.currentPage - page) + pagerState .currentPageOffsetFraction ).absoluteValue // We animate the alpha, between 50% and 100% alpha = lerp( start = 0.5f, stop = 1f, fraction = 1f - pageOffset.coerceIn(0f, 1f) ) } ) { // Card content } }
カスタム ページサイズ
デフォルトでは、HorizontalPager と VerticalPager はそれぞれ幅全体または高さ全体を使用します。pageSize 変数を
Fixed、Fill(デフォルト)、またはカスタム サイズ計算に設定できます。
たとえば、固定幅のページを 100.dp に設定するには、次のようにします。
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, pageSize = PageSize.Fixed(100.dp) ) { page -> // page content }
ビューポートのサイズに基づいてページをサイズ設定するには、カスタム ページサイズ計算を使用します。カスタム PageSize オブジェクトを作成し、項目間の間隔を考慮して
availableSpace を 3 で割ります。
private val threePagesPerViewport = object : PageSize { override fun Density.calculateMainAxisPageSize( availableSpace: Int, pageSpacing: Int ): Int { return (availableSpace - 2 * pageSpacing) / 3 } }
コンテンツのパディング
HorizontalPager と VerticalPager の両方でコンテンツのパディングを変更できます。これにより、ページの最大サイズと配置に影響します。
たとえば、start パディングを設定すると、ページが末尾に揃えられます。
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(start = 64.dp), ) { page -> // page content }
start パディングと end パディングの両方を同じ値に設定すると、項目が水平方向に中央揃えになります。
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(horizontal = 32.dp), ) { page -> // page content }
end パディングを設定すると、ページが先頭に揃えられます。
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(end = 64.dp), ) { page -> // page content }
top 値と bottom 値を設定すると、VerticalPager でも同様の効果が得られます。値 32.dp
は例としてのみ使用されます。パディングの各ディメンションには任意の値を設定できます。
スクロール動作をカスタマイズする
デフォルトの HorizontalPager コンポーザブルと VerticalPager
コンポーザブルは、スクロール操作がページャーでどのように機能するかを指定します。ただし、pagerSnapDistance や
flingBehavior などのデフォルトをカスタマイズして変更できます。
スナップ距離
デフォルトでは、HorizontalPager と VerticalPager は、フリング操作でスクロールできるページの最大数を一度に 1
ページに設定します。これを変更するには、pagerSnapDistance を flingBehavior で設定します。
val pagerState = rememberPagerState(pageCount = { 10 }) val fling = PagerDefaults.flingBehavior( state = pagerState, pagerSnapDistance = PagerSnapDistance.atMost(10) ) Column(modifier = Modifier.fillMaxSize()) { HorizontalPager( state = pagerState, pageSize = PageSize.Fixed(200.dp), beyondViewportPageCount = 10, flingBehavior = fling ) { PagerSampleItem(page = it) } }
自動進行ページャーを作成する
このセクションでは、Compose でページ インジケーターを使用して自動進行ページャーを作成する方法について説明します。項目のコレクションは自動的に水平方向にスクロールしますが、ユーザーは項目間を手動でスワイプすることもできます。ユーザーがページャーを操作すると、自動進行が停止します。
基本的な例
次のスニペットを組み合わせると、各ページが異なる色でレンダリングされるビジュアル インジケーターを備えた基本的な自動進行ページャーの実装が作成されます。
@Composable fun AutoAdvancePager(pageItems: List<Color>, modifier: Modifier = Modifier) { Box(modifier = Modifier.fillMaxSize()) { val pagerState = rememberPagerState(pageCount = { pageItems.size }) val pagerIsDragged by pagerState.interactionSource.collectIsDraggedAsState() val pageInteractionSource = remember { MutableInteractionSource() } val pageIsPressed by pageInteractionSource.collectIsPressedAsState() // Stop auto-advancing when pager is dragged or one of the pages is pressed val autoAdvance = !pagerIsDragged && !pageIsPressed if (autoAdvance) { LaunchedEffect(pagerState, pageInteractionSource) { while (true) { delay(2000) val nextPage = (pagerState.currentPage + 1) % pageItems.size pagerState.animateScrollToPage(nextPage) } } } HorizontalPager( state = pagerState ) { page -> Text( text = "Page: $page", textAlign = TextAlign.Center, modifier = modifier .fillMaxSize() .background(pageItems[page]) .clickable( interactionSource = pageInteractionSource, indication = LocalIndication.current ) { // Handle page click } .wrapContentSize(align = Alignment.Center) ) } PagerIndicator(pageItems.size, pagerState.currentPage) } }
コードに関する主なポイント
AutoAdvancePager関数は、自動進行する水平ページング ビューを作成します。入力としてColorオブジェクトのリストを受け取ります。これは、各ページの背景色として使用されます。pagerStateはrememberPagerStateを使用して作成されます。これは、ページャーの状態 を保持します。pagerIsDraggedとpageIsPressedはユーザー インタラクションを追跡します。LaunchedEffectは、 ユーザーがページャーをドラッグするか、いずれかのページを押さない限り、2 秒ごとにページャーを自動進行します。HorizontalPagerはページのリストを表示します。各ページには、ページ番号を表示するTextコンポーザブルが含まれています。この修飾子はページを塗りつぶし、pageItemsから背景色を設定し、ページをクリック可能にします。
@Composable fun PagerIndicator(pageCount: Int, currentPageIndex: Int, modifier: Modifier = Modifier) { Box(modifier = Modifier.fillMaxSize()) { Row( modifier = Modifier .wrapContentHeight() .fillMaxWidth() .align(Alignment.BottomCenter) .padding(bottom = 8.dp), horizontalArrangement = Arrangement.Center ) { repeat(pageCount) { iteration -> val color = if (currentPageIndex == iteration) Color.DarkGray else Color.LightGray Box( modifier = modifier .padding(2.dp) .clip(CircleShape) .background(color) .size(16.dp) ) } } } }
コードに関する主なポイント
- A
Boxコンポーザブルはルート要素として機能し、ページ インジケーターを水平方向に配置するRowを 含みます。 - カスタム ページ インジケーターは円の行として表示されます。
CircleShapeにクリップされた各Boxはページを表します。 - 現在のページの円は
DarkGrayで色付けされ、他の円はLightGrayです。currentPageIndexパラメータは、濃いグレーでレンダリングする円を指定します。
結果
この動画では、前のスニペットの基本的な自動進行ページャーが表示されます。