Tarik untuk me-refresh

Komponen tarik untuk memuat ulang memungkinkan pengguna menarik ke bawah di awal konten aplikasi untuk memuat ulang data.

Platform API

Gunakan composable PullToRefreshBox untuk menerapkan pull-to-refresh, yang bertindak sebagai penampung untuk konten yang dapat di-scroll. Parameter utama berikut mengontrol perilaku dan tampilan refresh:

  • isRefreshing: Nilai boolean yang menunjukkan apakah tindakan refresh saat ini sedang berlangsung.
  • onRefresh: Fungsi lambda yang dieksekusi saat pengguna memulai refresh.
  • indicator: Menyesuaikan indikator yang digambar pada pull-to-refresh.

Contoh dasar

Cuplikan ini menunjukkan penggunaan dasar PullToRefreshBox:

@Composable
fun PullToRefreshBasicSample(
    items: List<String>,
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
) {
    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = onRefresh,
        modifier = modifier
    ) {
        LazyColumn(Modifier.fillMaxSize()) {
            items(items) {
                ListItem({ Text(text = it) })
            }
        }
    }
}

Poin penting tentang kode

  • PullToRefreshBox menggabungkan LazyColumn, yang menampilkan daftar string.
  • PullToRefreshBox memerlukan parameter isRefreshing dan onRefresh.
  • Konten dalam blok PullToRefreshBox mewakili konten yang dapat di-scroll.

Hasil

Video ini menunjukkan implementasi pull-to-refresh dasar dari kode sebelumnya:

Gambar 1. Implementasi pull-to-refresh dasar pada daftar item.

Contoh lanjutan: Menyesuaikan warna indikator

@Composable
fun PullToRefreshCustomStyleSample(
    items: List<String>,
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
) {
    val state = rememberPullToRefreshState()

    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = onRefresh,
        modifier = modifier,
        state = state,
        indicator = {
            Indicator(
                modifier = Modifier.align(Alignment.TopCenter),
                isRefreshing = isRefreshing,
                containerColor = MaterialTheme.colorScheme.primaryContainer,
                color = MaterialTheme.colorScheme.onPrimaryContainer,
                state = state
            )
        },
    ) {
        LazyColumn(Modifier.fillMaxSize()) {
            items(items) {
                ListItem({ Text(text = it) })
            }
        }
    }
}

Poin penting tentang kode

  • Warna indikator disesuaikan melalui properti containerColor dan color dalam parameter indicator.
  • rememberPullToRefreshState() mengelola status tindakan refresh. Anda menggunakan status ini bersama dengan parameter indicator.

Hasil

Video ini menunjukkan implementasi pull-to-refresh dengan indikator berwarna:

Gambar 2. Implementasi pull-to-refresh dengan gaya kustom.

Contoh lanjutan: Membuat indikator yang sepenuhnya disesuaikan

Anda dapat membuat indikator kustom yang kompleks dengan memanfaatkan composable dan animasi yang ada.Cuplikan ini menunjukkan cara membuat indikator kustom sepenuhnya dalam implementasi pull-to-refresh:

@Composable
fun PullToRefreshCustomIndicatorSample(
    items: List<String>,
    isRefreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier
) {
    val state = rememberPullToRefreshState()

    PullToRefreshBox(
        isRefreshing = isRefreshing,
        onRefresh = onRefresh,
        modifier = modifier,
        state = state,
        indicator = {
            MyCustomIndicator(
                state = state,
                isRefreshing = isRefreshing,
                modifier = Modifier.align(Alignment.TopCenter)
            )
        }
    ) {
        LazyColumn(Modifier.fillMaxSize()) {
            items(items) {
                ListItem({ Text(text = it) })
            }
        }
    }
}

// ...
@Composable
fun MyCustomIndicator(
    state: PullToRefreshState,
    isRefreshing: Boolean,
    modifier: Modifier = Modifier,
) {
    Box(
        modifier = modifier.pullToRefreshIndicator(
            state = state,
            isRefreshing = isRefreshing,
            containerColor = PullToRefreshDefaults.containerColor,
            threshold = PositionalThreshold
        ),
        contentAlignment = Alignment.Center
    ) {
        Crossfade(
            targetState = isRefreshing,
            animationSpec = tween(durationMillis = CROSSFADE_DURATION_MILLIS),
            modifier = Modifier.align(Alignment.Center)
        ) { refreshing ->
            if (refreshing) {
                CircularProgressIndicator(Modifier.size(SPINNER_SIZE))
            } else {
                val distanceFraction = { state.distanceFraction.coerceIn(0f, 1f) }
                Icon(
                    imageVector = Icons.Filled.CloudDownload,
                    contentDescription = "Refresh",
                    modifier = Modifier
                        .size(18.dp)
                        .graphicsLayer {
                            val progress = distanceFraction()
                            this.alpha = progress
                            this.scaleX = progress
                            this.scaleY = progress
                        }
                )
            }
        }
    }
}

Poin penting tentang kode

  • Cuplikan sebelumnya menggunakan Indicator yang disediakan oleh library. Cuplikan ini membuat composable indikator kustom yang disebut MyCustomIndicator. Dalam composable ini, pengubah pullToRefreshIndicator menangani pemosisian dan memicu refresh.
  • Seperti pada cuplikan sebelumnya, instance PullToRefreshState telah diekstrak, sehingga instance yang sama dapat diteruskan ke PullToRefreshBox dan pullToRefreshModifier.
  • Warna penampung dan nilai minimum posisi digunakan dari class PullToRefreshDefaults. Dengan cara ini, Anda dapat menggunakan kembali perilaku dan gaya default dari library Material, sekaligus menyesuaikan hanya elemen yang Anda minati.
  • MyCustomIndicator menggunakan Crossfade untuk bertransisi antara ikon cloud dan CircularProgressIndicator. Ikon cloud diskalakan saat pengguna menarik, dan bertransisi ke CircularProgressIndicator saat tindakan refresh dimulai.
    • targetState menggunakan isRefreshing untuk menentukan status yang akan ditampilkan (ikon cloud atau indikator progres melingkar).
    • animationSpec menentukan animasi tween untuk transisi, dengan durasi CROSSFADE_DURATION_MILLIS yang ditentukan.
    • state.distanceFraction menunjukkan seberapa jauh pengguna telah menarik ke bawah, mulai dari 0f (tidak menarik) hingga 1f (ditarik sepenuhnya).
    • Pengubah graphicsLayer mengubah skala dan transparansi.

Hasil

Video ini menampilkan indikator kustom dari kode sebelumnya:

Gambar 3. Implementasi pull-to-refresh dengan indikator kustom.

Referensi lainnya