Aby przewijać treści w poziomie lub w pionie, możesz użyć funkcji kompozycyjnych HorizontalPager
i VerticalPager
. Mają one podobne funkcje do ViewPager
w systemie wyświetlania. Domyślnie element
HorizontalPager
zajmuje całą szerokość ekranu, a element VerticalPager
– całą wysokość. Powiadomienia te wyświetlają tylko jedną stronę naraz. Wszystkie te ustawienia domyślne można skonfigurować.
HorizontalPager
Aby utworzyć pager, który przewija się w lewo i w prawo, użyj tego kodu: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
Aby utworzyć pager, który przewija się w górę i w dół, użyj tego kodu: VerticalPager
VerticalPager
// Display 10 items val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier.fillMaxWidth() ) }
Leniwe tworzenie
Strony w HorizontalPager
i VerticalPager
są komponowane i układane na żądanie. Gdy użytkownik przewija strony, funkcja kompozycyjna usuwa wszystkie strony, które nie są już potrzebne.
Wczytywanie większej liczby stron poza ekranem
Domyślnie pager wczytuje tylko widoczne na ekranie strony. Aby wczytać więcej stron poza ekranem, ustaw wartość beyondBoundsPageCount
większą niż zero.
Przewiń do elementu w pagerze
Aby przewinąć do określonej strony w pagerze, utwórz obiekt PagerState
za pomocą rememberPagerState()
i przekaż go jako parametr state
do pagera. W tym stanie możesz zadzwonić pod numer PagerState#scrollToPage()
w ramach 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") }
Jeśli chcesz animować przejście do strony, użyj funkcji 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") }
Otrzymywanie powiadomień o zmianach stanu strony
PagerState
ma 3 właściwości z informacjami o stronach: currentPage
, settledPage
i targetPage
.
currentPage
: Najbliższa strona do pozycji przyciągania. Domyślnie pozycja przyciągania jest na początku układu.settledPage
: numer strony, gdy nie jest uruchomiona animacja ani przewijanie. Różni się to od właściwościcurrentPage
, ponieważcurrentPage
natychmiast się aktualizuje, jeśli strona jest wystarczająco blisko pozycji przyciągania, alesettledPage
pozostaje bez zmian, dopóki nie zostaną zakończone wszystkie animacje.targetPage
: proponowana pozycja zatrzymania przewijania.
Możesz użyć funkcji snapshotFlow
, aby obserwować zmiany tych zmiennych i na nie reagować. Aby na przykład wysyłać zdarzenie analityczne przy każdej zmianie strony, możesz wykonać te czynności:
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") }
Dodawanie wskaźnika strony
Aby dodać wskaźnik do strony, użyj obiektu PagerState
, aby uzyskać informacje o tym, która strona jest wybrana spośród wszystkich stron, i narysuj niestandardowy wskaźnik.
Aby na przykład utworzyć wskaźnik w postaci kółek, możesz powtórzyć liczbę kółek i zmienić kolor kółka w zależności od tego, czy strona jest wybrana, używając tego kodu: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) ) } }

Stosowanie efektów przewijania elementów do treści
Częstym przypadkiem użycia jest stosowanie efektów do elementów pagera na podstawie pozycji przewijania. Aby dowiedzieć się, jak daleko od wybranej strony znajduje się dana strona, możesz użyć PagerState.currentPageOffsetFraction
. Następnie możesz zastosować efekty przekształcenia do treści na podstawie odległości od wybranej strony.
Aby na przykład dostosować krycie elementów w zależności od tego, jak daleko znajdują się od środka, zmień wartość alpha
za pomocą Modifier.graphicsLayer
w elemencie w przeglądarce stron:
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 } }
Niestandardowe rozmiary stron
Domyślnie elementy HorizontalPager
i VerticalPager
zajmują odpowiednio całą szerokość lub całą wysokość. Zmienna pageSize
może mieć wartość Fixed
, Fill
(domyślną) lub niestandardowe obliczenia rozmiaru.
Na przykład aby ustawić stronę o stałej szerokości 100.dp
:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, pageSize = PageSize.Fixed(100.dp) ) { page -> // page content }
Aby dopasować rozmiar stron do rozmiaru widocznego obszaru, użyj niestandardowego obliczania rozmiaru strony. Utwórz niestandardowy obiekt PageSize
i podziel availableSpace
przez 3, uwzględniając odstępy między elementami:
private val threePagesPerViewport = object : PageSize { override fun Density.calculateMainAxisPageSize( availableSpace: Int, pageSpacing: Int ): Int { return (availableSpace - 2 * pageSpacing) / 3 } }
Wypełnienie treści
HorizontalPager
i VerticalPager
obsługują zmianę dopełnienia treści, co pozwala wpływać na maksymalny rozmiar i wyrównanie stron.
Na przykład ustawienie dopełnienia start
wyrównuje strony do końca:

val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(start = 64.dp), ) { page -> // page content }
Ustawienie dopełnienia start
i end
na tę samą wartość wyśrodkuje element w poziomie:

val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(horizontal = 32.dp), ) { page -> // page content }
Ustawienie dopełnienia end
powoduje wyrównanie stron do początku:

val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(end = 64.dp), ) { page -> // page content }
Możesz ustawić wartości top
i bottom
, aby uzyskać podobne efekty w przypadku
VerticalPager
. Wartość 32.dp
jest tu używana tylko jako przykład. Możesz ustawić dowolną wartość dla każdego z wymiarów dopełnienia.
Dostosowywanie przewijania
Domyślne funkcje kompozycyjne HorizontalPager
i VerticalPager
określają, jak gesty przewijania działają w przypadku komponentu do stronicowania. Możesz jednak dostosować i zmienić ustawienia domyślne, takie jak pagerSnapDistance
lub flingBehavior
.
Odległość przyciągania
Domyślnie HorizontalPager
i VerticalPager
ustawiają maksymalną liczbę stron, o którą można przewinąć za pomocą gestu szybkiego przesunięcia, na 1 stronę naraz. Aby to zmienić, ustaw pagerSnapDistance
w 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) } }
Tworzenie automatycznie przewijanej strony
Z tej sekcji dowiesz się, jak utworzyć automatycznie przewijany pager ze wskaźnikami stron w Compose. Kolekcja elementów przewija się automatycznie w poziomie, ale użytkownicy mogą też ręcznie przesuwać między nimi. Jeśli użytkownik wejdzie w interakcję z pagerem, automatyczne przełączanie zostanie zatrzymane.
Podstawowy przykład
Poniższe fragmenty kodu tworzą podstawową implementację automatycznie przewijanego pagera ze wskaźnikiem wizualnym, w którym każda strona jest renderowana w innym kolorze:
@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) } }
Najważniejsze informacje o kodzie
- Funkcja
AutoAdvancePager
tworzy widok z przewijaniem w poziomie i automatycznym przechodzeniem do następnej strony. Jako dane wejściowe przyjmuje listę obiektówColor
, które są używane jako kolory tła poszczególnych stron. pagerState
jest tworzony za pomocą funkcjirememberPagerState
, która przechowuje stan stronicowania.pagerIsDragged
ipageIsPressed
śledzą interakcje użytkowników.LaunchedEffect
automatycznie przełącza strony co 2 sekundy, chyba że użytkownik przeciągnie stronę lub naciśnie jedną z nich.HorizontalPager
wyświetla listę stron, z których każda zawieraText
komponent wyświetlający numer strony. Modyfikator wypełnia stronę, ustawia kolor tła zpageItems
i sprawia, że można ją kliknąć.
@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) ) } } } }
Najważniejsze informacje o kodzie
- Kompozycja
Box
działa jako element główny i zawieraRow
, który służy do rozmieszczania wskaźników strony w poziomie. - Niestandardowy wskaźnik strony jest wyświetlany jako rząd kółek, z których każde
Box
przycięte doCircleShape
reprezentuje stronę. - Okrąg bieżącej strony jest oznaczony kolorem
DarkGray
, a pozostałe okręgi – koloremLightGray
. ParametrcurrentPageIndex
określa, który okrąg ma być renderowany w kolorze ciemnoszarym.
Wynik
Ten film przedstawia podstawowy pager z automatycznym przełączaniem stron z poprzednich fragmentów kodu: