Pager in der Funktion „Schreiben“

Mit den zusammensetzbaren Funktionen HorizontalPager und VerticalPager können Sie nach links und rechts bzw. nach oben und unten durch Inhalte blättern. Diese zusammensetzbaren Funktionen haben im Ansichtssystem ähnliche Funktionen wie ViewPager. Standardmäßig nimmt HorizontalPager die volle Breite des Bildschirms ein, VerticalPager die volle Höhe und die Pager öffnen jeweils nur eine Seite. Diese Standardeinstellungen sind konfigurierbar.

HorizontalPager

Verwenden Sie HorizontalPager, um einen Pager zu erstellen, der horizontal nach links und rechts scrollt:

Abbildung 1: Demo von 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 Pager zu erstellen, der nach oben und unten scrollt:

Abbildung 2: Demo von VerticalPager

// Display 10 items
val pagerState = rememberPagerState(pageCount = {
    10
})
VerticalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier.fillMaxWidth()
    )
}

Verzögerte Erstellung

Die Seiten in HorizontalPager und VerticalPager werden bei Bedarf lazit zusammengestellt und angeordnet. Wenn der Nutzer durch die Seiten scrollt, entfernt die zusammensetzbare Funktion alle Seiten, die nicht mehr benötigt werden.

Weitere Seiten außerhalb des Bildschirms laden

Standardmäßig werden auf dem Pager nur die sichtbaren Seiten geladen. Wenn Sie mehr Seiten außerhalb des sichtbaren Bereichs laden möchten, legen Sie für beyondBoundsPageCount einen Wert größer als null fest.

Zu einem Element auf der Seite scrollen

Wenn Sie auf dem Pager zu einer bestimmten Seite scrollen möchten, erstellen Sie mit rememberPagerState() ein PagerState-Objekt und übergeben Sie es als state-Parameter an den Pager. Sie können PagerState#scrollToPage() für diesen Status in einem 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 zu Änderungen des Seitenstatus erhalten

PagerState hat drei Attribute mit Informationen zu Seiten: currentPage, settledPage und targetPage.

  • currentPage: Die Seite, die der Andockposition am nächsten ist. 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 Attribut currentPage insofern, als currentPage sofort aktualisiert wird, wenn die Seite nah genug an der Andockposition ist. settledPage bleibt jedoch gleich, bis alle Animationen ausgeführt wurden.
  • targetPage: Die vorgeschlagene Stoppposition 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 Analyseereignis:

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")
}

Seitenwechsel hinzufügen

Wenn Sie einer Seite einen Indikator hinzufügen möchten, rufen Sie mit dem Objekt PagerState Informationen dazu ab, welche Seite aus der Anzahl der Seiten ausgewählt wurde, und zeichnen Sie den benutzerdefinierten Indikator.

Wenn Sie beispielsweise eine einfache Kreisanzeige verwenden möchten, können Sie die Anzahl der Kreise wiederholen und die Kreisfarbe mit 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)
        )
    }
}

Pager mit einem Kreissymbol unter dem Inhalt
Abbildung 3: Pager mit einem Kreissymbol unter dem Inhalt

Scrolleffekte von Elementen auf Inhalte anwenden

Ein häufiger Anwendungsfall ist die Verwendung der Scrollposition, um Effekte auf Ihre Pager-Elemente anzuwenden. Mit PagerState.currentPageOffsetFraction können Sie ermitteln, wie weit eine Seite von der aktuell ausgewählten Seite entfernt ist. Anschließend können Sie Transformationseffekte basierend auf der Entfernung von der ausgewählten Seite auf Ihre Inhalte anwenden.

Abbildung 4: Transformationen auf Pager-Inhalte anwenden

Wenn Sie beispielsweise die Deckkraft von Elementen abhängig davon anpassen möchten, wie weit sie von der Mitte entfernt sind, ändern Sie alpha mit Modifier.graphicsLayer für ein Element auf dem 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 Seitengrößen

Standardmäßig nehmen HorizontalPager und VerticalPager die volle Breite bzw. Höhe ein. Sie können für die Variable pageSize entweder Fixed, Fill (Standard) oder eine benutzerdefinierte Größenberechnung festlegen.

So legen Sie beispielsweise eine Seite mit fester 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 basierend auf der Größe des Darstellungsbereichs anpassen möchten, verwenden Sie eine benutzerdefinierte Berechnung der Seitengröße. Erstellen Sie ein benutzerdefiniertes PageSize-Objekt und teilen Sie 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
    }
}

Abstände im Inhalt

Sowohl HorizontalPager als auch VerticalPager unterstützen das Ändern des Abstands für den Inhalt, sodass Sie die maximale Größe und Ausrichtung von Seiten beeinflussen können.

Wenn Sie beispielsweise den Abstand start festlegen, werden die Seiten am Ende ausgerichtet:

Pager mit einem Abstand am Anfang, bei dem der Inhalt am Ende ausgerichtet ist

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(start = 64.dp),
) { page ->
    // page content
}

Wenn Sie den Abstand für start und end auf denselben Wert festlegen, wird das Element horizontal zentriert:

Pager mit einem Abstand an Anfang und Ende, bei dem der Inhalt in der Mitte angezeigt wird

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(horizontal = 32.dp),
) { page ->
    // page content
}

Wenn Sie den Abstand end festlegen, werden die Seiten am Anfang ausgerichtet:

Pager mit einem Abstand am Anfang und Ende, bei dem der Inhalt am Anfang ausgerichtet ist

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 Abmessung einen beliebigen Wert festlegen.

Scrollverhalten anpassen

Die standardmäßigen zusammensetzbaren Funktionen HorizontalPager und VerticalPager geben an, wie Scrollbewegungen mit dem Pager funktionieren. Sie können die Standardeinstellungen wie pagerSnapDistance oder flingBehavior jedoch anpassen und ändern.

Abstand

Standardmäßig legen HorizontalPager und VerticalPager die maximale Anzahl von Seiten fest, die mit einer Fingergeste auf eine Seite gescrollt werden können. 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),
        beyondBoundsPageCount = 10,
        flingBehavior = fling
    ) {
        PagerSampleItem(page = it)
    }
}