Pager di Compose

Untuk membalik konten dengan cara kiri dan kanan atau atas dan bawah, Anda dapat menggunakan tindakan HorizontalPager dan VerticalPager composable. Composable ini memiliki fungsi yang mirip dengan ViewPager di tampilan sistem file. Secara default, HorizontalPager memenuhi lebar layar, VerticalPager menempati tinggi penuh, dan pager hanya mengayunkan satu halaman baik. Semua setelan default ini dapat dikonfigurasi.

HorizontalPager

Untuk membuat ringkasan yang dapat di-scroll ke kiri dan ke kanan secara horizontal, gunakan HorizontalPager:

Gambar 1. Demo HorizontalPager

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

VerticalPager

Untuk membuat halaman yang dapat di-scroll ke atas dan ke bawah, gunakan VerticalPager:

Gambar 2. Demo VerticalPager

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

Pembuatan lambat

Halaman di HorizontalPager dan VerticalPager lambat tersusun dan ditata saat diperlukan. Sebagai pengguna men-scroll halaman, composable menghapus halaman yang tidak lagi tidak diperlukan.

Muat halaman lainnya di luar layar

Secara default, halaman hanya memuat halaman yang terlihat di layar. Untuk memuat halaman lainnya di luar layar, setel beyondBoundsPageCount ke nilai yang lebih tinggi dari nol.

Scroll ke item di halaman

Untuk men-scroll ke halaman tertentu dalam Pager, buat PagerState objek menggunakan rememberPagerState() dan teruskan sebagai parameter state ke Pager. Anda dapat memanggil PagerState#scrollToPage() di status ini, di dalam 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")
}

Jika Anda ingin menganimasikan halaman, gunakan PagerState#animateScrollToPage() {i>function<i}:

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

Mendapatkan notifikasi tentang perubahan status halaman

PagerState memiliki tiga properti dengan informasi tentang halaman: currentPage, settledPage, dan targetPage.

  • currentPage: Halaman yang paling dekat dengan posisi snap. Secara default, snap berada di awal tata letak.
  • settledPage: Nomor halaman saat tidak ada animasi atau scroll yang berjalan. Ini berbeda dengan properti currentPage yang di dalamnya currentPage segera diperbarui jika laman cukup dekat dengan posisi, tetapi settledPage tetap sama hingga semua animasi selesai berjalan.
  • targetPage: Posisi perhentian yang diusulkan untuk gerakan scroll.

Anda dapat menggunakan fungsi snapshotFlow untuk mengamati perubahan pada variabel ini dan bereaksi terhadapnya. Misalnya, untuk mengirim peristiwa analisis pada setiap perubahan halaman, Anda dapat melakukan hal berikut:

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

Menambahkan indikator halaman

Untuk menambahkan indikator ke halaman, gunakan objek PagerState untuk mendapatkan informasi tentang halaman mana yang dipilih dari jumlah halaman, dan buat gambar indikator.

Misalnya, jika Anda menginginkan indikator lingkaran sederhana, Anda dapat mengulangi jumlah lingkaran dan mengubah warna lingkaran berdasarkan pada apakah laman itu dipilih, menggunakan 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 yang menampilkan indikator lingkaran di bawah konten
Gambar 3. Pager yang menampilkan indikator lingkaran di bawah konten

Menerapkan efek scroll item ke konten

Kasus penggunaan yang umum adalah menggunakan posisi scroll untuk menerapkan efek ke halaman Anda item. Untuk mengetahui seberapa jauh jarak halaman dari halaman yang saat ini dipilih, Anda dapat penggunaan PagerState.currentPageOffsetFraction Kemudian, Anda dapat menerapkan efek transformasi ke konten berdasarkan jaraknya dari halaman yang dipilih.

Gambar 4. Menerapkan transformasi pada konten Pager

Misalnya, untuk menyesuaikan opasitas item berdasarkan seberapa jauh item tersebut dari tengah, ubah alpha menggunakan Modifier.graphicsLayer pada item di dalam halaman:

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

Ukuran halaman kustom

Secara default, HorizontalPager dan VerticalPager menggunakan lebar penuh atau tinggi penuh. Anda dapat menetapkan variabel pageSize agar memiliki Fixed, Fill (default), atau penghitungan ukuran kustom.

Misalnya, untuk menetapkan halaman dengan lebar tetap 100.dp:

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

Untuk menyesuaikan ukuran halaman berdasarkan ukuran area pandang, gunakan ukuran halaman kustom kalkulasi. Buat kustom PageSize dan bagi availableSpace dengan tiga, dengan mempertimbangkan jaraknya antara item:

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

Padding konten

HorizontalPager dan VerticalPager mendukung perubahan padding konten, yang memungkinkan Anda memengaruhi ukuran dan perataan maksimum halaman.

Misalnya, menyetel padding start akan menyelaraskan halaman ke bagian akhir:

Pager dengan padding awal yang menampilkan konten disejajarkan ke bagian akhir

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

Menetapkan padding start dan end ke nilai yang sama akan menempatkan item di tengah horizontal:

Pager dengan padding awal dan akhir yang menampilkan konten berada di tengah

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

Menyetel padding end akan menyelaraskan halaman ke awal:

Pager dengan padding awal dan akhir yang menampilkan konten diselaraskan dengan awal

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

Anda dapat menetapkan nilai top dan bottom untuk mencapai efek serupa untuk VerticalPager. Nilai 32.dp hanya digunakan di sini sebagai contoh; kamu bisa atur setiap dimensi padding ke nilai apa pun.

Menyesuaikan perilaku scroll

Composable HorizontalPager dan VerticalPager default menentukan cara {i>gestures <i}scroll{i> <i}berfungsi pada {i>slideshow<i}. Namun, Anda dapat menyesuaikan dan mengubah default seperti pagerSnapDistance atau flingBehavior.

Jarak snap

Secara default, HorizontalPager dan VerticalPager menetapkan jumlah maksimum halaman yang dapat di-{i>rolling <i}melewati ke satu halaman dalam satu waktu. Untuk mengubah ini, setel pagerSnapDistance pada flingBehavior:

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