Trascina per aggiornare

Il componente Pull to refresh consente agli utenti di trascinare verso il basso all'inizio dei contenuti di un'app per aggiornare i dati.

Superficie API

Utilizza il componente componibile PullToRefreshBox per implementare il trascinamento verso il basso per aggiornare, che funge da contenitore per i contenuti scorrevoli. I seguenti parametri chiave controllano il comportamento e l'aspetto dell'aggiornamento:

  • isRefreshing: un valore booleano che indica se l'azione di aggiornamento è in corso.
  • onRefresh: una funzione Lambda che viene eseguita quando l'utente avvia un aggiornamento.
  • indicator: Personalizza l'indicatore che il sistema disegna quando si scorre verso il basso per aggiornare la pagina.

Esempio di base

Questo snippet mostra l'utilizzo di base di 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) })
            }
        }
    }
}

Punti chiave del codice

  • PullToRefreshBox racchiude un elemento LazyColumn, che mostra un elenco di stringhe.
  • PullToRefreshBox richiede i parametri isRefreshing e onRefresh.
  • I contenuti all'interno del blocco PullToRefreshBox rappresentano i contenuti scorrevoli.

Risultato

Questo video mostra l'implementazione di base del trascinamento per aggiornare dal codice precedente:

Figura 1. Un'implementazione di base del trascinamento per aggiornare un elenco di elementi.

Esempio avanzato: personalizzare il colore dell'indicatore

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

Punti chiave del codice

  • Il colore dell'indicatore viene personalizzato tramite le proprietà containerColor e color nel parametro indicator.
  • rememberPullToRefreshState() gestisce lo stato dell'azione di aggiornamento. Utilizzi questo stato insieme al parametro indicator.

Risultato

Questo video mostra un'implementazione del trascinamento per aggiornare con un indicatore colorato:

Figura 2. Un'implementazione di pull-to-refresh con uno stile personalizzato.

Esempio avanzato: crea un indicatore completamente personalizzato

Puoi creare indicatori personalizzati complessi sfruttando i composable e le animazioni esistenti.Questo snippet mostra come creare un indicatore completamente personalizzato nell'implementazione del 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
                        }
                )
            }
        }
    }
}

Punti chiave del codice

  • Lo snippet precedente utilizzava Indicator fornito dalla libreria. Questo snippet crea un composable indicatore personalizzato denominato MyCustomIndicator. In questo componibile, il modificatore pullToRefreshIndicator gestisce il posizionamento e l'attivazione di un aggiornamento.
  • Come nello snippet precedente, l'esempio estrae l'istanza PullToRefreshState, in modo da poter passare la stessa istanza sia a PullToRefreshBox sia a pullToRefreshModifier.
  • L'esempio utilizza il colore del contenitore e la soglia di posizione della classe PullToRefreshDefaults. In questo modo, puoi riutilizzare il comportamento e lo stile predefiniti della libreria Material, personalizzando solo gli elementi che ti interessano.
  • MyCustomIndicator utilizza Crossfade per passare da un'icona cloud a un CircularProgressIndicator. L'icona del cloud aumenta di dimensioni quando l'utente tira e si trasforma in un CircularProgressIndicator quando inizia l'azione di aggiornamento.
    • targetState utilizza isRefreshing per determinare lo stato da visualizzare (l'icona del cloud o l'indicatore di avanzamento circolare).
    • animationSpec definisce un'animazione tween per la transizione, con una durata specificata di CROSSFADE_DURATION_MILLIS.
    • state.distanceFraction rappresenta quanto l'utente ha tirato verso il basso, da 0f (nessun tiro) a 1f (tiro completo).
    • Il modificatore graphicsLayer modifica la scala e la trasparenza.

Risultato

Questo video mostra l'indicatore personalizzato del codice precedente:

Figura 3. Un'implementazione di pull-to-refresh con un indicatore personalizzato.

Risorse aggiuntive