Per sfogliare i contenuti da sinistra a destra o dall'alto verso il basso, puoi utilizzare i composable
HorizontalPager
e
VerticalPager
, rispettivamente. Questi composable hanno funzioni simili a
ViewPager
nel sistema
di visualizzazione. Per impostazione predefinita, HorizontalPager
occupa l'intera larghezza dello schermo,
VerticalPager
occupa l'intera altezza e i pager scorrono solo una 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 componente rimovibile elimina le pagine che non sono 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 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 transizione alla 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 aggancio si trova 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, se vuoi un semplice indicatore a cerchio, puoi ripetere il numero di cerchi e cambiare 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 a quale distanza si trova una pagina da quella attualmente 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
(valore 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 sia per start
che per 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, ad esempio 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 a 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 componente componibileText
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 elemento componibile
Box
viene utilizzato come elemento principale.- All'interno di
Box
, un elemento componibileRow
dispone gli indicatori di pagina orizzontalmente.
- All'interno di
- Un indicatore di pagina personalizzato viene visualizzato come una riga di cerchi, dove ogni
Box
ritagliato in uncircle
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: