Para folhear o conteúdo da esquerda para a direita ou de cima para baixo, use os elementos combináveis
HorizontalPager
e
VerticalPager
, respectivamente. Esses elementos combináveis têm funções semelhantes a
ViewPager
no sistema
de visualização. Por padrão, a HorizontalPager
ocupa toda a largura da tela, a VerticalPager
ocupa toda a altura, e os pagers só deslizam uma página por vez. Todos esses padrões podem ser configurados.
HorizontalPager
Para criar um pager que role horizontalmente para a esquerda e para a direita, use
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
Para criar um pager que rola para cima e para baixo, use VerticalPager
:
VerticalPager
// Display 10 items val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier.fillMaxWidth() ) }
Criação lenta
As páginas em HorizontalPager
e VerticalPager
são compostas
de forma lenta e dispostas quando necessário. À medida que o usuário
rola as páginas, o elemento combinável remove as que não são mais
necessárias.
Carregar mais páginas fora da tela
Por padrão, o pager carrega apenas as páginas visíveis na tela. Para carregar mais páginas
fora da tela, defina beyondBoundsPageCount
como um valor maior que zero.
Rolar até um item no pager
Para rolar até uma determinada página no pager, crie um
objeto PagerState
usando
rememberPagerState()
e transmita-o como o parâmetro state
ao pager. Você pode chamar
PagerState#scrollToPage()
nesse estado, dentro de um 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 quiser animar a página, use a
função
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") }
Receber notificações sobre mudanças no estado da página
O PagerState
tem três propriedades com informações sobre páginas:
currentPage
,
settledPage
e
targetPage
.
currentPage
: a página mais próxima da posição de ajuste. Por padrão, a posição de ajuste é no início do layout.settledPage
: o número da página quando nenhuma animação ou rolagem está em execução. Isso é diferente da propriedadecurrentPage
, já quecurrentPage
é atualizado imediatamente se a página estiver perto o suficiente da posição de ajuste, massettledPage
permanece o mesmo até que todas as animações sejam concluídas.targetPage
: a posição de parada proposta para um movimento de rolagem.
Use a função snapshotFlow
para observar e reagir a mudanças nessas variáveis. Por exemplo, para enviar um evento do Google Analytics a cada mudança de página,
faça o seguinte:
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") }
Adicionar um indicador de página
Para adicionar um indicador a uma página, use o objeto PagerState
para receber informações
sobre qual página está selecionada entre o número de páginas e desenhe seu indicador
personalizado.
Por exemplo, se você quiser um indicador de círculo simples, repita o número de círculos e mude a cor com base em se a página está selecionada, usando 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) ) } }

Aplicar efeitos de rolagem de itens ao conteúdo
Um caso de uso comum é usar a posição de rolagem para aplicar efeitos aos itens do pager. Para saber a distância de uma página da página selecionada no momento, use PagerState.currentPageOffsetFraction
.
Em seguida, aplique efeitos de transformação ao conteúdo com base na distância da página selecionada.
Por exemplo, para ajustar a opacidade dos itens com base na distância deles do centro, mude o alpha
usando Modifier.graphicsLayer
em um item dentro do 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 } }
Tamanhos de página personalizados
Por padrão, HorizontalPager
e VerticalPager
ocupam toda a largura ou
toda a altura, respectivamente. É possível definir a variável pageSize
para ter um
Fixed
,
Fill
(padrão) ou um cálculo de tamanho personalizado.
Por exemplo, para definir uma página de largura fixa de 100.dp
:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, pageSize = PageSize.Fixed(100.dp) ) { page -> // page content }
Para dimensionar as páginas com base no tamanho da janela de visualização, use um cálculo personalizado de tamanho da página. Crie um objeto
PageSize
personalizado e divida o availableSpace
por três, considerando o espaçamento
entre os itens:
private val threePagesPerViewport = object : PageSize { override fun Density.calculateMainAxisPageSize( availableSpace: Int, pageSpacing: Int ): Int { return (availableSpace - 2 * pageSpacing) / 3 } }
Padding de conteúdo
HorizontalPager
e VerticalPager
permitem mudar o padding do conteúdo, o que influencia o tamanho máximo e o alinhamento das páginas.
Por exemplo, definir o padding start
alinha as páginas até o final:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(start = 64.dp), ) { page -> // page content }
Definir o padding start
e end
com o mesmo valor centraliza o item
horizontalmente:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(horizontal = 32.dp), ) { page -> // page content }
Definir o padding end
alinha as páginas ao início:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(end = 64.dp), ) { page -> // page content }
É possível definir os valores top
e bottom
para conseguir efeitos semelhantes em
VerticalPager
. O valor 32.dp
é usado aqui apenas como um exemplo. Você pode definir cada uma das dimensões de padding com qualquer valor.
Personalizar o comportamento de rolagem
Os elementos combináveis HorizontalPager
e VerticalPager
padrão especificam como
gestos de rolagem funcionam com o pager. No entanto, é possível personalizar e mudar os padrões, como pagerSnapDistance
ou flingBehavior
.
Distância de ajuste
Por padrão, HorizontalPager
e VerticalPager
definem o número máximo de páginas que um gesto de deslizar pode rolar de uma página por vez. Para mudar isso, defina pagerSnapDistance
no 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) } }
Criar um pager de avanço automático
Esta seção descreve como criar um pager de avanço automático com indicadores de página no Compose. A coleção de itens rola automaticamente na horizontal, mas os usuários também podem deslizar manualmente entre eles. Se um usuário interagir com o pager, a progressão automática será interrompida.
Exemplo básico
Juntos, os snippets a seguir criam uma implementação básica de pager de avanço automático com um indicador visual, em que cada página é renderizada como uma cor diferente:
@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) } }
Pontos principais sobre o código
- A função
AutoAdvancePager
cria uma visualização de paginação horizontal com avanço automático. Ele usa uma lista de objetosColor
como entrada, que são usados como cores de segundo plano para cada página. - O
pagerState
é criado usandorememberPagerState
, que contém o estado do pager. pagerIsDragged
epageIsPressed
rastreiam a interação do usuário.- O
LaunchedEffect
avança automaticamente o pager a cada dois segundos, a menos que o usuário arraste ou pressione uma das páginas. HorizontalPager
mostra uma lista de páginas, cada uma com um elemento combinávelText
que mostra o número da página. O modificador preenche a página, define a cor do plano de fundo depageItems
e torna a página clicável.
@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) ) } } } }
Pontos principais sobre o código
- Um elemento combinável
Box
é usado como o elemento raiz.- Dentro do
Box
, um elemento combinávelRow
organiza os indicadores de página horizontalmente.
- Dentro do
- Um indicador de página personalizado é mostrado como uma linha de círculos, em que cada
Box
cortado em umcircle
representa uma página. - O círculo da página atual é colorido como um
DarkGray
, enquanto os outros círculos sãoLightGray
. O parâmetrocurrentPageIndex
determina qual círculo será renderizado em cinza escuro.
Resultado
Este vídeo mostra o pager básico de avanço automático dos snippets anteriores: