Aby przewijać treści w lewo i w prawo lub w górę i w dół, możesz użyć odpowiednio funkcji kompozycyjnych HorizontalPager
i VerticalPager
. Te funkcje kompozycyjne mają podobne funkcje do ViewPager
w systemie widoków. Domyślnie HorizontalPager
zajmuje całą szerokość ekranu, VerticalPager
– całą wysokość, a pagery przewijają 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 na żądanie i układane w razie potrzeby. Gdy użytkownik przewija strony, komponent usuwa te, 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. Możesz wywołać
PagerState#scrollToPage()
w tym stanie 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 zakończą się 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.
Jeśli na przykład chcesz użyć prostego wskaźnika w postaci kółka, możesz powtórzyć liczbę kółek i zmienić ich kolor 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 sprawdzić, jak daleko od aktualnie wybranej strony znajduje się dana strona, możesz użyć PagerState.currentPageOffsetFraction
.
Następnie możesz zastosować do treści efekty przekształcenia 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ą funkcji Modifier.graphicsLayer
w elemencie w pagerze:
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ść. Zmienną pageSize
możesz ustawić tak, aby miała wartość Fixed
, Fill
(domyślnie) 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 obiekt niestandardowy
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 start
padding 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
wyrównuje strony 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
na 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
- Jako element główny używany jest komponent
Box
.- W komponencie
Box
komponentRow
rozmieszcza wskaźniki stron w poziomie.
- W komponencie
- Niestandardowy wskaźnik strony jest wyświetlany jako rząd kółek, z których każde
Box
przycięte docircle
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: