Per sfogliare i contenuti orizzontalmente o verticalmente, puoi utilizzare i composable
HorizontalPager
e VerticalPager
. Questi hanno funzioni simili a ViewPager
nel sistema di visualizzazione. Per impostazione predefinita,
HorizontalPager
occupa l'intera larghezza dello schermo e VerticalPager
occupa
l'intera altezza. Inoltre, i pager scorrono una sola pagina alla volta. Tutti questi
valori predefiniti sono configurabili.
HorizontalPager
Per creare un pager che scorre orizzontalmente a sinistra e a destra, utilizza
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
Per creare un pager che scorre verso l'alto e verso il basso, utilizza VerticalPager
:
VerticalPager
// Display 10 items val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier.fillMaxWidth() ) }
Lazy creation
Le pagine sia in HorizontalPager
che in VerticalPager
sono composte in modo differito
e disposte quando necessario. Man mano che l'utente scorre le pagine, il composable
rimuove le pagine non più necessarie.
Caricare più pagine fuori dallo schermo
Per impostazione predefinita, il pager carica solo le pagine visibili sullo schermo. Per caricare più pagine
fuori schermo, imposta beyondBoundsPageCount
su un valore maggiore di zero.
Scorrere fino a un elemento nel pager
Per scorrere fino a una determinata pagina nel pager, crea un oggetto PagerState
utilizzando rememberPagerState()
e passalo come parametro state
al
pager. Puoi chiamare PagerState#scrollToPage()
in questo stato, all'interno di un
CoroutineScope
:
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") }
Se vuoi animare la pagina, utilizza la funzione
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") }
Ricevere notifiche sulle modifiche dello stato della pagina
PagerState
ha tre proprietà con informazioni sulle pagine:
currentPage
, settledPage
e targetPage
.
currentPage
: La pagina più vicina alla posizione dello snap. Per impostazione predefinita, la posizione di allineamento è all'inizio del layout.settledPage
: il numero di pagina quando non è in esecuzione alcuna animazione o scorrimento. Questo è diverso dalla proprietàcurrentPage
in quantocurrentPage
si aggiorna immediatamente se la pagina è abbastanza vicina alla posizione di snap, masettledPage
rimane invariato fino al termine dell'esecuzione di tutte le animazioni.targetPage
: La posizione di arresto proposta per un movimento di scorrimento.
Puoi utilizzare la funzione snapshotFlow
per osservare le modifiche a queste variabili
e reagire di conseguenza. Ad esempio, per inviare un evento Analytics a ogni cambio di pagina,
puoi procedere nel seguente modo:
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") }
Aggiungere un indicatore di pagina
Per aggiungere un indicatore a una pagina, utilizza l'oggetto PagerState
per ottenere informazioni
su quale pagina è selezionata rispetto al numero di pagine e disegna l'indicatore
personalizzato.
Ad esempio, per creare un indicatore circolare, puoi ripetere il numero di
cerchi e modificare il colore del cerchio in base alla selezione della pagina, utilizzando
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) ) } }

Applicare effetti di scorrimento degli elementi ai contenuti
Un caso d'uso comune è utilizzare la posizione di scorrimento per applicare effetti agli elementi del pager. Per scoprire la distanza di una pagina da quella selezionata, puoi utilizzare
PagerState.currentPageOffsetFraction
. Puoi quindi applicare effetti di trasformazione
ai tuoi contenuti in base alla distanza dalla pagina selezionata.
Ad esempio, per regolare l'opacità degli elementi in base alla distanza dal centro, modifica alpha
utilizzando Modifier.graphicsLayer
su un elemento all'interno del pager:
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 } }
Dimensioni pagina personalizzate
Per impostazione predefinita, HorizontalPager
e VerticalPager
occupano rispettivamente l'intera larghezza o
l'intera altezza. Puoi impostare la variabile pageSize
in modo che abbia un valore
Fixed
, Fill
(predefinito) o un calcolo personalizzato delle dimensioni.
Ad esempio, per impostare una pagina a larghezza fissa di 100.dp
:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, pageSize = PageSize.Fixed(100.dp) ) { page -> // page content }
Per dimensionare le pagine in base alle dimensioni dell'area visibile, utilizza un calcolo personalizzato delle dimensioni della pagina. Crea un oggetto PageSize
personalizzato e dividi
availableSpace
per tre, tenendo conto della spaziatura tra gli elementi:
private val threePagesPerViewport = object : PageSize { override fun Density.calculateMainAxisPageSize( availableSpace: Int, pageSpacing: Int ): Int { return (availableSpace - 2 * pageSpacing) / 3 } }
Spazio interno dei contenuti
HorizontalPager
e VerticalPager
supportano entrambi la modifica del padding dei contenuti,
che ti consente di influire sulle dimensioni e sull'allineamento massimi delle pagine.
Ad esempio, l'impostazione del padding start
allinea le pagine verso la fine:

val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(start = 64.dp), ) { page -> // page content }
Se imposti la stessa spaziatura interna per start
e end
, l'elemento viene centrato
orizzontalmente:

val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(horizontal = 32.dp), ) { page -> // page content }
L'impostazione del padding end
allinea le pagine all'inizio:

val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(end = 64.dp), ) { page -> // page content }
Puoi impostare i valori top
e bottom
per ottenere effetti simili per
VerticalPager
. Il valore 32.dp
viene utilizzato qui solo come esempio; puoi impostare
ciascuna delle dimensioni del padding su qualsiasi valore.
Personalizzare il comportamento di scorrimento
I composable HorizontalPager
e VerticalPager
predefiniti specificano il funzionamento
dei gesti di scorrimento con il pager. Tuttavia, puoi personalizzare e modificare
le impostazioni predefinite, come pagerSnapDistance
o flingBehavior
.
Distanza di aggancio
Per impostazione predefinita, HorizontalPager
e VerticalPager
impostano il numero massimo di pagine che un gesto di scorrimento può scorrere a una pagina alla volta. Per modificare
questa impostazione, imposta pagerSnapDistance
su 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) } }
Crea un pager ad avanzamento automatico
Questa sezione descrive come creare un pager con avanzamento automatico con indicatori di pagina in Compose. La raccolta di elementi scorre automaticamente in orizzontale, ma gli utenti possono anche scorrere manualmente tra gli elementi. Se un utente interagisce con il pager, la progressione automatica si interrompe.
Esempio di base
I seguenti snippet creano insieme un'implementazione di base di un pager con avanzamento automatico con un indicatore visivo, in cui ogni pagina viene visualizzata con un colore diverso:
@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) } }
Punti chiave del codice
- La funzione
AutoAdvancePager
crea una visualizzazione con paginazione orizzontale e avanzamento automatico. Prende come input un elenco di oggettiColor
, che vengono utilizzati come colori di sfondo per ogni pagina. pagerState
viene creato utilizzandorememberPagerState
, che contiene lo stato del pager.pagerIsDragged
epageIsPressed
tengono traccia dell'interazione degli utenti.LaunchedEffect
fa avanzare automaticamente il pager ogni due secondi, a meno che l'utente non lo trascini o non prema una delle pagine.HorizontalPager
mostra un elenco di pagine, ognuna con un componenteText
che mostra il numero di pagina. Il modificatore riempie la pagina, imposta il colore di sfondo dapageItems
e rende la pagina cliccabile.
@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) ) } } } }
Punti chiave del codice
- Un componente componibile
Box
funge da elemento principale e contiene unRow
per disporre gli indicatori di pagina orizzontalmente. - Un indicatore di pagina personalizzato viene visualizzato come una riga di cerchi, dove ogni
Box
ritagliato in unCircleShape
rappresenta una pagina. - Il cerchio della pagina corrente è colorato come
DarkGray
, mentre gli altri cerchi sonoLightGray
. Il parametrocurrentPageIndex
determina quale cerchio viene visualizzato in grigio scuro.
Risultato
Questo video mostra il pager di avanzamento automatico di base degli snippet precedenti: