Mit den Composables HorizontalPager
und VerticalPager
kannst du Inhalte nach links und rechts oder nach oben und unten durchblättern. Diese Elemente haben ähnliche Funktionen wie ViewPager
im Ansichtssystem. Standardmäßig nimmt das HorizontalPager
die volle Breite des Bildschirms ein, VerticalPager
die volle Höhe. Die Seitenblätter springen jeweils nur eine Seite weiter. Diese Standardeinstellungen sind alle konfigurierbar.
HorizontalPager
Wenn Sie einen Bildlauf erstellen möchten, der horizontal nach links und rechts scrollt, verwenden Sie 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
Verwenden Sie VerticalPager
, um einen Bildlauf, der nach oben und unten scrollt, zu erstellen:
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
Seiten in HorizontalPager
und VerticalPager
werden lazily komponiert und bei Bedarf layoutet. Wenn der Nutzer durch die Seiten scrollt, werden alle Seiten entfernt, die nicht mehr erforderlich sind.
Mehr Seiten im Hintergrund laden
Standardmäßig werden mit dem Bildlauf nur die sichtbaren Seiten auf dem Bildschirm geladen. Wenn Sie mehr Seiten im Hintergrund laden möchten, setzen Sie beyondBoundsPageCount
auf einen Wert größer als null.
In der Bildlaufleiste zu einem Element scrollen
Wenn Sie zum Scrollen zu einer bestimmten Seite im Paginierungselement ein PagerState
-Objekt erstellen möchten, verwenden Sie rememberPagerState()
und übergeben Sie es als state
-Parameter an das Paginierungselement. Sie können PagerState#scrollToPage()
in diesem Status innerhalb eines CoroutineScope
aufrufen:
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") }
Wenn Sie die Seite animieren möchten, verwenden Sie die Funktion 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") }
Benachrichtigungen bei Änderungen des Seitenstatus erhalten
PagerState
hat drei Properties mit Informationen zu Seiten:
currentPage
,
settledPage
und
targetPage
.
currentPage
: Die Seite, die der Anlegeposition am nächsten ist. Standardmäßig befindet sich die Anlegeposition am Anfang des Layouts.settledPage
: Die Seitennummer, wenn keine Animation oder kein Scrollen ausgeführt wird. Das unterscheidet sich von der EigenschaftcurrentPage
, dacurrentPage
sofort aktualisiert wird, wenn sich die Seite nahe genug an der Anlegeposition befindet.settledPage
bleibt jedoch unverändert, bis alle Animationen abgeschlossen sind.targetPage
: Die vorgeschlagene Endposition für eine Scrollbewegung.
Mit der Funktion snapshotFlow
können Sie Änderungen an diesen Variablen beobachten und darauf reagieren. So senden Sie beispielsweise bei jeder Seitenänderung ein Analytics-Ereignis:
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") }
Seitenindikator hinzufügen
Wenn Sie einer Seite einen Indikator hinzufügen möchten, verwenden Sie das PagerState
-Objekt, um Informationen dazu zu erhalten, welche Seite aus der Anzahl der Seiten ausgewählt ist, und zeichnen Sie Ihren benutzerdefinierten Indikator.
Wenn Sie beispielsweise einen einfachen Kreisindikator benötigen, können Sie die Anzahl der Kreise wiederholen und die Kreisfarbe mithilfe von pagerState.currentPage
ändern, je nachdem, ob die Seite ausgewählt ist:
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) ) } }

Scrolleffekte für Elemente auf Inhalte anwenden
Ein häufiger Anwendungsfall ist die Verwendung der Scrollposition, um Effekte auf die Elemente des Bildlaufs anzuwenden. Mit PagerState.currentPageOffsetFraction
können Sie herausfinden, wie weit eine Seite von der aktuell ausgewählten entfernt ist.
Sie können dann Transformationseffekte auf Ihre Inhalte anwenden, die sich an der Entfernung von der ausgewählten Seite orientieren.
Wenn Sie beispielsweise die Deckkraft von Elementen anhand ihrer Entfernung vom Mittelpunkt anpassen möchten, ändern Sie den alpha
mit Modifier.graphicsLayer
für ein Element im 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 } }
Benutzerdefinierte Seitenformate
Standardmäßig nehmen HorizontalPager
und VerticalPager
jeweils die volle Breite oder Höhe ein. Sie können die Variable pageSize
entweder auf Fixed
, Fill
(Standard) oder eine benutzerdefinierte Größenberechnung festlegen.
So legen Sie beispielsweise eine Seite mit einer festen Breite von 100.dp
fest:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, pageSize = PageSize.Fixed(100.dp) ) { page -> // page content }
Wenn Sie die Seitengröße anhand der Darstellungsgröße festlegen möchten, verwenden Sie eine benutzerdefinierte Berechnung der Seitengröße. Erstellen Sie ein benutzerdefiniertes PageSize
-Objekt und teilen Sie die availableSpace
durch drei, wobei Sie den Abstand zwischen den Elementen berücksichtigen:
private val threePagesPerViewport = object : PageSize { override fun Density.calculateMainAxisPageSize( availableSpace: Int, pageSpacing: Int ): Int { return (availableSpace - 2 * pageSpacing) / 3 } }
Textabstand
Sowohl HorizontalPager
als auch VerticalPager
unterstützen das Ändern des Inhaltsabstands, mit dem Sie die maximale Größe und Ausrichtung von Seiten beeinflussen können.
Wenn Sie beispielsweise das start
-Abstand festlegen, werden die Seiten am Ende ausgerichtet:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(start = 64.dp), ) { page -> // page content }
Wenn Sie sowohl für den start
- als auch für den end
-Abstand denselben Wert festlegen, wird das Element horizontal zentriert:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(horizontal = 32.dp), ) { page -> // page content }
Wenn Sie den end
-Abstand festlegen, werden die Seiten am Anfang ausgerichtet:
val pagerState = rememberPagerState(pageCount = { 4 }) HorizontalPager( state = pagerState, contentPadding = PaddingValues(end = 64.dp), ) { page -> // page content }
Sie können die Werte für top
und bottom
festlegen, um ähnliche Effekte für VerticalPager
zu erzielen. Der Wert 32.dp
wird hier nur als Beispiel verwendet. Sie können jede der Abstände auf einen beliebigen Wert festlegen.
Scrollverhalten anpassen
Die Standard-Composables HorizontalPager
und VerticalPager
geben an, wie Scrollgesten mit dem Pager funktionieren. Sie können die Standardeinstellungen wie pagerSnapDistance
oder flingBehavior
jedoch anpassen und ändern.
Snap-Distanz
Standardmäßig legen HorizontalPager
und VerticalPager
die maximale Anzahl von Seiten fest, die mit einer Wischgeste jeweils übersprungen werden können. Wenn Sie das ändern möchten, legen Sie auf der flingBehavior
die Option pagerSnapDistance
fest:
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) } }
Ein automatisch weiterlaufendes Anzeigefeld erstellen
In diesem Abschnitt wird beschrieben, wie Sie in Compose einen automatischen Bildlauf mit Seitenindikatoren erstellen. Die Artikel werden automatisch horizontal gescrollt, Nutzer können aber auch manuell zwischen den Artikeln wischen. Wenn ein Nutzer mit dem Pager interagiert, wird die automatische Weiterleitung gestoppt.
Einfaches Beispiel
Zusammengenommen bilden die folgenden Snippets eine grundlegende Implementierung eines automatischen Pagers mit einem visuellen Indikator, bei dem jede Seite in einer anderen Farbe dargestellt wird:
@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) } }
Wichtige Punkte zum Code
- Die Funktion
AutoAdvancePager
erstellt eine horizontale Ansicht mit automatischer Weiterleitung. Als Eingabe wird eine Liste vonColor
-Objekten verwendet, die als Hintergrundfarben für jede Seite verwendet werden. pagerState
wird mitrememberPagerState
erstellt, das den Status des Pagers enthält.pagerIsDragged
undpageIsPressed
erfassen Nutzerinteraktionen.- Mit der Taste
LaunchedEffect
wird der Bildlauf alle zwei Sekunden automatisch fortgesetzt, es sei denn, der Nutzer zieht den Bildlauf oder drückt eine der Seiten. HorizontalPager
zeigt eine Liste von Seiten mit jeweils einemText
-Element an, auf dem die Seitennummer angezeigt wird. Der Modifier füllt die Seite, legt die Hintergrundfarbe vonpageItems
fest und macht die Seite anklickbar.
@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) ) } } } }
Wichtige Punkte zum Code
- Als Stammelement wird ein
Box
-Komposit verwendet.- Innerhalb des
Box
ordnet einRow
-Element die Seitenindikatoren horizontal an.
- Innerhalb des
- Ein benutzerdefinierter Seitenindikator wird als Reihe von Kreisen dargestellt, wobei jeder
Box
, der an einencircle
angehängt ist, eine Seite darstellt. - Der Kreis der aktuellen Seite ist
DarkGray
, die anderen Kreise sindLightGray
. Mit dem ParametercurrentPageIndex
wird festgelegt, welcher Kreis dunkelgrau dargestellt wird.
Ergebnis
In diesem Video wird der grundlegende automatisch weiterlaufende Pager aus den vorherigen Snippets angezeigt:
Derzeit liegen keine Empfehlungen vor.
Versuchen Sie, sich bei Ihrem Google-Konto anzumelden.