Pager w sekcji Utwórz

Do przełączania treści w lewo i w prawo lub w górę i w dół możesz używać HorizontalPager oraz VerticalPager elementów kompozycyjnych. Te elementy kompozycyjne mają podobne funkcje ViewPager w widoku systemu. Domyślnie HorizontalPager zajmuje całą szerokość ekranu, Obszar VerticalPager zajmuje całą wysokość, a pagery pomijają tylko jedną stronę. obecnie się znajdujesz. Wszystkie te wartości domyślne możesz skonfigurować.

HorizontalPager

Aby utworzyć pager, który przewija się w poziomie w lewo i w prawo, użyj HorizontalPager:

Rysunek 1. Wersja demonstracyjna: 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 elementu VerticalPager:

Rysunek 2. Wersja demonstracyjna: 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 językach: HorizontalPager i VerticalPager działają leniwie skomponowane i rozmieszczone w razie potrzeby. Jako użytkownik przewija strony, funkcja kompozycyjna usuwa wszystkie strony, które już nie są

Wczytywanie większej liczby stron poza ekranem

Domyślnie pager wczytuje tylko strony widoczne na ekranie. Aby wczytać więcej stron poza ekranem, ustaw beyondBoundsPageCount na wartość większą niż 0.

Przewiń do elementu na stronie pagera

Aby przewinąć do określonej strony na stronie, utwórz PagerState za pomocą rememberPagerState() i przekazać go do pagera jako parametr state. Możesz zadzwonić do nas, PagerState#scrollToPage() w tym stanie, w elemencie 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, żeby strona była animowana, użyj PagerState#animateScrollToPage() funkcja:

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, oraz targetPage.

  • currentPage: strona, która znajduje się najbliższa położeniemu przyciągania. Domyślnie przyciąganie pozycja jest na początku układu.
  • settledPage: numer strony, gdy nie jest uruchomiona żadna animacja ani przewijanie. Ten różni się od właściwości currentPage tym, że currentPage natychmiast aktualizuje się, gdy strona jest wystarczająco blisko miejsca przyciągania, ale Wartość settledPage pozostaje bez zmian, dopóki wszystkie animacje nie zostaną zakończone.
  • targetPage: proponowana pozycja zatrzymania przewijania.

Możesz użyć funkcji snapshotFlow, aby obserwować zmiany tych zmiennych i reagować na nie. Aby np. 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")
}

Dodaj wskaźnik strony

Aby dodać wskaźnik do strony, użyj obiektu PagerState do uzyskania informacji na temat tego, która strona jest wybrana z liczby stron, i narysuj własny wskaźnik.

Na przykład jeśli chcesz używać prostego wskaźnika okręgu, możesz powtórzyć liczbę i zmień ich kolor w zależności od tego, czy wybrana jest strona 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 z ikoną koła pod treścią
Rysunek 3. Pager z ikoną koła pod treścią

Zastosuj efekty przewijania elementów do treści

Typowym przypadkiem użycia jest użycie pozycji przewijania do zastosowania efektów do pagera. elementy(ów). Aby dowiedzieć się, jak daleko od wybranej strony znajduje się strona, możesz należy użyć funkcji PagerState.currentPageOffsetFraction Następnie możesz zastosować efekty przekształceniowe do treści dostosowane do odległości z wybranej strony.

Rysunek 4. Zastosowanie przekształceń do treści pagera

Aby na przykład dostosować przezroczystość elementów na podstawie ich odległości od obrazu w środku, zmień alpha za pomocą Modifier.graphicsLayer na elemencie na stronie pagera:

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 HorizontalPager i VerticalPager zajmują pełną szerokość lub pełnej wysokości. Możesz ustawić zmienną pageSize tak, aby miała parametr Fixed, Fill (domyślna) lub obliczenia rozmiaru niestandardowego.

Aby na przykład ustawić stronę o stałej szerokości strony 100.dp:

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    pageSize = PageSize.Fixed(100.dp)
) { page ->
    // page content
}

Aby zmienić rozmiar strony na podstawie rozmiaru widocznego obszaru, użyj niestandardowego rozmiaru strony obliczeń. Utwórz niestandardową PageSize i podziel availableSpace przez trzy, biorąc pod uwagę odstępy między elementami:

private val threePagesPerViewport = object : PageSize {
    override fun Density.calculateMainAxisPageSize(
        availableSpace: Int,
        pageSpacing: Int
    ): Int {
        return (availableSpace - 2 * pageSpacing) / 3
    }
}

Dopełnienie treści

Zarówno HorizontalPager, jak i VerticalPager umożliwiają zmianę dopełnienia treści, co pozwala dostosować maksymalny rozmiar i wyrównanie stron.

Na przykład ustawienie dopełnienia start spowoduje wyrównanie strony do końca:

Pager z dopełnieniem początkowym pokazującym treść wyrównaną 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 ma taką samą wartość, względem którego wyśrodkowuje się element w poziomie:

Pager z dopełnieniem na początku i na końcu przedstawiającym treść wyśrodkowaną

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

Ustawienie dopełnienia end powoduje wyrównanie położenia stron na początku:

Pager z dopełnieniem początkowym i końcowym przedstawiającym treść wyrównaną do początku

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

Aby uzyskać podobne efekty, możesz ustawić wartości top i bottom. VerticalPager Wartość 32.dp została użyta tylko jako przykład. możesz ustawić wymiarów dopełnienia na dowolną wartość.

Dostosowywanie działania przewijania

Domyślne kompozycje HorizontalPager i VerticalPager określają, jak gesty przewijania działają z pagerem. Możesz jednak dostosować i zmienić wartości domyślne, takie jak pagerSnapDistance lub flingBehavior.

Odległość przyciągania

Domyślnie HorizontalPager i VerticalPager ustawiają maksymalną liczbę strony, z których gest przesunięcia może przejść do jednej strony naraz. Aby zmienić to, ustaw pagerSnapDistanceflingBehavior:

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