Mit den zusammensetzbaren Funktionen
HorizontalPager und VerticalPager können Sie horizontal oder vertikal durch Inhalte blättern. Sie haben
ähnliche Funktionen wie ViewPager im Ansichtssystem. Standardmäßig nimmt HorizontalPager die gesamte Bildschirmbreite und VerticalPager die gesamte Höhe ein. Außerdem wird mit den Pager-Elementen jeweils nur eine Seite weitergeblättert. Alle diese Standardeinstellungen sind konfigurierbar.
HorizontalPager
Verwenden Sie HorizontalPager, um ein Pager-Element zu erstellen, das horizontal nach links und rechts scrollt:
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 ein Pager-Element zu erstellen, das nach oben und unten scrollt:
VerticalPager
// Display 10 items val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPager(state = pagerState) { page -> // Our page content Text( text = "Page: $page", modifier = Modifier.fillMaxWidth() ) }
Lazy-Erstellung
Seiten in HorizontalPager und VerticalPager werden lazy zusammengesetzt
und bei Bedarf angeordnet. Wenn der Nutzer durch die Seiten scrollt, werden alle nicht mehr benötigten Seiten von der zusammensetzbaren Funktion entfernt.
Weitere Seiten außerhalb des Bildschirms laden
Standardmäßig werden im Pager-Element nur die sichtbaren Seiten auf dem Bildschirm geladen. Wenn Sie weitere Seiten außerhalb des Bildschirms laden möchten, legen Sie für beyondBoundsPageCount einen Wert über null fest.
Zu einem Element im Pager-Element scrollen
Wenn Sie zu einer bestimmten Seite im Pager-Element scrollen möchten, erstellen Sie ein PagerState-Objekt
mit rememberPagerState() und übergeben Sie es als state-Parameter an das
Pager-Element. 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 zur Seite animieren möchten, verwenden Sie die
PagerState#animateScrollToPage() Funktion:
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 am Seitenstatus erhalten
PagerState hat drei Attribute mit Informationen zu Seiten:
currentPage, settledPage und targetPage.
currentPage: Die Seite, die der Position am nächsten ist, an der das Scrollen beendet wird. Standardmäßig befindet sich die Andockposition am Anfang des Layouts.settledPage: Die Seitenzahl, wenn keine Animation oder kein Scrollen ausgeführt wird. Dies unterscheidet sich vom AttributcurrentPage, dacurrentPagesofort aktualisiert wird, wenn sich die Seite nahe genug an der Position befindet, an der das Scrollen beendet wird.settledPagebleibt jedoch gleich, 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. Wenn Sie beispielsweise bei jeder Seitenänderung ein Analytics-Ereignis senden möchten, können Sie so vorgehen:
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 Kreisindikator erstellen möchten, können Sie die Anzahl der Kreise wiederholen und die Farbe des Kreises ändern, je nachdem, ob die Seite ausgewählt ist. Verwenden Sie dazu 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) ) } }
Scroll-Effekte auf Inhalte anwenden
Ein häufiger Anwendungsfall ist, die Scrollposition zu verwenden, um Effekte auf die Pager-Elemente anzuwenden. Mit
PagerState.currentPageOffsetFraction können Sie herausfinden, wie weit eine Seite von der ausgewählten Seite entfernt ist. Anschließend können Sie Transformations-Effekte auf Ihre Inhalte anwenden, je nachdem, wie weit sie von der ausgewählten Seite entfernt sind.
Wenn Sie beispielsweise die Deckkraft von Elementen anpassen möchten, je nachdem, wie weit sie vom
Mittelpunkt entfernt sind, ändern Sie den Wert von alpha mit Modifier.graphicsLayer für ein Element
im Pager-Element:
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 Seitengrößen
Standardmäßig nehmen HorizontalPager und VerticalPager die gesamte Breite bzw. Höhe ein. Sie können die Variable pageSize 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 Größe der Seiten an die Größe des Darstellungsbereichs anpassen möchten, verwenden Sie eine benutzerdefinierte Berechnung der Seitengröße. Erstellen Sie ein benutzerdefiniertes PageSize-Objekt und teilen Sie die
availableSpace durch drei. Berücksichtigen Sie dabei den Abstand zwischen den Elementen:
private val threePagesPerViewport = object : PageSize { override fun Density.calculateMainAxisPageSize( availableSpace: Int, pageSpacing: Int ): Int { return (availableSpace - 2 * pageSpacing) / 3 } }
Content-Padding
Sowohl HorizontalPager als auch VerticalPager unterstützen das Ändern des Content-Paddings. So können Sie die maximale Größe und Ausrichtung von Seiten beeinflussen.
Wenn Sie beispielsweise das start-Padding 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 das start- als auch das end-Padding auf 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 das end-Padding 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 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 für jede der Padding-Dimensionen einen beliebigen Wert festlegen.
Scrollverhalten anpassen
Die Standard-Composables HorizontalPager und VerticalPager geben an, wie Scrollgesten mit dem Pager-Element funktionieren. Sie können jedoch die Standardeinstellungen anpassen und ändern, z. B. pagerSnapDistance oder flingBehavior.
Abstand für das Einrasten
Standardmäßig legen HorizontalPager und VerticalPager die maximale Anzahl von Seiten fest, die mit einer zügigen Wischbewegung weitergescrollt werden können. Es wird jeweils nur eine Seite weitergescrollt. Wenn Sie
dies ändern möchten, legen Sie pagerSnapDistance für flingBehavior 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) } }
Pager-Element mit automatischer Weiterbewegung erstellen
In diesem Abschnitt wird beschrieben, wie Sie in Compose ein Pager-Element mit automatischer Weiterbewegung und Seitenindikatoren erstellen. Die Elementkollektion wird automatisch horizontal gescrollt. Nutzer können aber auch manuell zwischen den Elementen wischen. Wenn ein Nutzer mit dem Pager-Element interagiert, wird die automatische Weiterbewegung beendet.
Einfaches Beispiel
Mit den folgenden Code-Snippets wird eine einfache Pager-Implementierung mit automatischer Weiterbewegung und einem visuellen Indikator erstellt, bei der jede Seite in einer anderen Farbe gerendert 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 Informationen zum Code
- Die Funktion
AutoAdvancePagererstellt eine horizontal blätternde Ansicht mit automatischer Weiterbewegung. Sie verwendet eine Liste vonColor-Objekten als Eingabe, die als Hintergrundfarben für die einzelnen Seiten verwendet werden. pagerStatewird mitrememberPagerStateerstellt und enthält den Status des Pager-Elements.pagerIsDraggedundpageIsPressedverfolgen die Nutzerinteraktion.- Das
LaunchedEffectauto-advances the pager every two seconds unless the user drags the pager or presses one of the pages. HorizontalPagerzeigt eine Liste von Seiten an, die jeweils einText-Composable enthalten, das die Seitenzahl anzeigt. Der Modifier füllt die Seite, legt die Hintergrundfarbe auspageItemsfest und macht die Seite klickbar.
@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 Informationen zum Code
- Ein
Box-Composable dient als Stammelement und enthält eineRow, um die Seitenindikatoren horizontal anzuordnen. - Ein benutzerdefinierter Seitenindikator wird als Reihe von Kreisen angezeigt, wobei jede
Box, die auf eineCircleShapezugeschnitten ist, eine Seite darstellt. - Der Kreis der aktuellen Seite ist
DarkGray, die anderen Kreise sindLightGray. Der ParametercurrentPageIndexbestimmt, welcher Kreis dunkelgrau gerendert wird.
Ergebnis
In diesem Video wird das einfache Pager-Element mit automatischer Weiterbewegung aus den vorherigen Code-Snippets gezeigt: