Pager in der Funktion „Schreiben“

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

HorizontalPager

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

Abbildung 1: Demo zu 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 zu VerticalPager

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

Verzögertes Erstellen

Seiten in HorizontalPager und VerticalPager werden verzögert zusammengesetzt und bei Bedarf neu angelegt. Wenn der Nutzer durch die Seiten scrollt, werden alle nicht mehr benötigten Seiten von der zusammensetzbaren Funktion entfernt.

Weitere nicht sichtbare Seiten laden

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

Zu einem Element auf dem Pager scrollen

Wenn Sie zu einer bestimmten Seite im Pager scrollen möchten, erstellen Sie mit rememberPagerState() ein PagerState-Objekt und übergeben Sie es als state-Parameter an den Pager. Sie können für diesen Status PagerState#scrollToPage() 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")
}

Benachrichtigung bei Änderungen des Seitenstatus

PagerState hat drei Properties 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: Seitennummer, wenn keine Animation oder kein Scrollen ausgeführt wird. Dies unterscheidet sich von der Eigenschaft currentPage dadurch, dass 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 können Sie beispielsweise bei jeder Seitenänderung ein Analyseereignis senden:

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 Objekt PagerState, um Informationen darüber zu erhalten, 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 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)
        )
    }
}

Pager mit einer Kreisanzeige unter dem Inhalt
Abbildung 3: Pager mit einer kreisförmigen Anzeige unter dem Inhalt

Scrolleffekte von Elementen auf Inhalte anwenden

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

Abbildung 4: Transformationen auf Pager-Inhalte anwenden

Wenn Sie beispielsweise die Deckkraft von Elementen anpassen möchten, je nachdem, wie weit sie von der Mitte entfernt sind, ändern Sie alpha mithilfe von 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. die volle Höhe ein. Sie können die Variable pageSize so festlegen, dass sie entweder Fixed, Fill (Standardeinstellung) oder eine benutzerdefinierte Größenberechnung hat.

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
}

Um die Größe der Seiten basierend auf dem Darstellungsbereich anzupassen, 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 zwischen Inhalten

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

Wenn Sie beispielsweise den Abstand von start festlegen, werden die Seiten zum Ende hin ausgerichtet:

Pager mit Abstand am Anfang, Inhalt ist am Ende ausgerichtet

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

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

Pager mit Abstand am Anfang und Ende, der Inhalt ist zentriert

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

Durch Festlegen des Abstands von end werden die Seiten zum Anfang ausgerichtet:

Pager mit Abstand am Anfang und Ende, auf 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 Auswirkungen für VerticalPager zu erzielen. Der Wert 32.dp wird hier nur als Beispiel verwendet. Sie können für jede der Innenabstände einen beliebigen Wert festlegen.

Scrollverhalten anpassen

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

Abstand zum Andocken

Mit HorizontalPager und VerticalPager legen Sie standardmäßig die maximale Anzahl von Seiten fest, bei denen mit einer fließenden Touch-Geste jeweils eine Seite weiterscrollt. Wenn Sie dies ändern möchten, legen Sie pagerSnapDistance auf 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)
    }
}