Trascina per aggiornare

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

API surface

Utilizza il composable PullToRefreshBox per implementare il riavvio con trazione, 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 è attualmente in corso.
  • onRefresh: una funzione lambda che viene eseguita quando l'utente avvia un aggiornamento.
  • indicator: personalizza l'indicatore disegnato con il gesto di scorrimento per aggiornare.

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 inserisce un 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 riavvio con un gesto dal codice precedente:

Figura 1. Un'implementazione di base di scorrimento verso il basso per aggiornare un elenco di elementi.

Esempio avanzato: personalizzazione del 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. Utilizza questo stato in combinazione con il parametro indicator.

Risultato

Questo video mostra un'implementazione del gesto di scorrimento per aggiornare con un indicatore colorato:

Figura 2. Un'implementazione di Aggiorna trascinando con uno stile personalizzato.

Esempio avanzato: crea un indicatore completamente personalizzato

Puoi creare indicatori personalizzati complessi sfruttando composabili e 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 composable, il modificatore pullToRefreshIndicator gestisce il posizionamento e l'attivazione di un aggiornamento.
  • Come nello snippet precedente, l'istanza PullToRefreshState è stata estratta, pertanto la stessa istanza può essere passata sia a PullToRefreshBox sia a pullToRefreshModifier.
  • Il colore del contenitore e la soglia di posizione vengono utilizzati dalla classe PullToRefreshDefaults. In questo modo, puoi riutilizzare il comportamento e lo stile predefiniti della raccolta Material, personalizzando solo gli elementi che ti interessano.
  • MyCustomIndicator utilizza Crossfade per passare da un'icona a forma di nuvola a un CircularProgressIndicator. L'icona del cloud aumenta di dimensioni man mano che l'utente esegue lo scorrimento e diventa CircularProgressIndicator quando inizia l'azione di aggiornamento.
    • targetState utilizza isRefreshing per determinare quale stato visualizzare (l'icona a forma di nuvola o l'indicatore di avanzamento circolare).
    • animationSpec definisce un'animazione tween per la transizione, con una durata specificata di CROSSFADE_DURATION_MILLIS.
    • state.distanceFraction indica quanto l'utente ha tirato verso il basso, da 0f (nessuna trazione) a 1f (trazione completa).
    • Il modificatore graphicsLayer modifica la scala e la trasparenza.

Risultato

Questo video mostra l'indicatore personalizzato del codice precedente:

Figura 3. Un'implementazione di aggiornamento con un indicatore personalizzato.

Risorse aggiuntive