Faire glisser pour actualiser

Le composant "Tirer pour actualiser" permet aux utilisateurs de faire glisser leur doigt vers le bas au début du contenu d'une application pour actualiser les données.

Surface d'API

Utilisez le composable PullToRefreshBox pour implémenter l'actualisation par balayage, qui sert de conteneur pour votre contenu défilant. Les paramètres clés suivants contrôlent le comportement et l'apparence de l'actualisation :

  • isRefreshing : valeur booléenne indiquant si l'action d'actualisation est en cours.
  • onRefresh : fonction lambda qui s'exécute lorsque l'utilisateur lance une actualisation.
  • indicator : personnalise l'indicateur que le système dessine lors de l'actualisation par balayage.

Exemple de base

Cet extrait montre l'utilisation de base de 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) })
            }
        }
    }
}

Points clés concernant le code

  • PullToRefreshBox encapsule un LazyColumn, qui affiche une liste de chaînes.
  • PullToRefreshBox nécessite les paramètres isRefreshing et onRefresh.
  • Le contenu du bloc PullToRefreshBox représente le contenu déroulant.

Résultat

Cette vidéo montre l'implémentation de base de l'actualisation par balayage à partir du code précédent :

Figure 1. Implémentation de base de l'actualisation par balayage sur une liste d'éléments.

Exemple avancé : personnaliser la couleur de l'indicateur

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

Points clés concernant le code

  • La couleur de l'indicateur est personnalisée à l'aide des propriétés containerColor et color du paramètre indicator.
  • rememberPullToRefreshState() gère l'état de l'action d'actualisation. Vous utilisez cet état conjointement avec le paramètre indicator.

Résultat

Cette vidéo montre une implémentation de l'actualisation par balayage avec un indicateur de couleur :

Figure 2. Implémentation d'un style personnalisé pour l'actualisation par balayage vers le bas.

Exemple avancé : créer un indicateur entièrement personnalisé

Vous pouvez créer des indicateurs personnalisés complexes en tirant parti des composables et des animations existants.Cet extrait montre comment créer un indicateur entièrement personnalisé dans votre implémentation de l'actualisation par balayage :

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

Points clés concernant le code

  • L'extrait précédent utilisait le Indicator fourni par la bibliothèque. Cet extrait crée un composable d'indicateur personnalisé appelé MyCustomIndicator. Dans ce composable, le modificateur pullToRefreshIndicator gère le positionnement et le déclenchement d'une actualisation.
  • Comme dans l'extrait précédent, l'exemple extrait l'instance PullToRefreshState. Vous pouvez donc transmettre la même instance à PullToRefreshBox et à pullToRefreshModifier.
  • L'exemple utilise la couleur du conteneur et le seuil de positionnement de la classe PullToRefreshDefaults. Vous pouvez ainsi réutiliser le comportement et le style par défaut de la bibliothèque Material, tout en personnalisant uniquement les éléments qui vous intéressent.
  • MyCustomIndicator utilise Crossfade pour passer d'une icône Cloud à un CircularProgressIndicator. L'icône cloud s'agrandit lorsque l'utilisateur tire l'écran vers le bas, puis passe à CircularProgressIndicator lorsque l'action d'actualisation commence.
    • targetState utilise isRefreshing pour déterminer l'état à afficher (l'icône en forme de nuage ou l'indicateur de progression circulaire).
    • animationSpec définit une animation tween pour la transition, avec une durée spécifiée de CROSSFADE_DURATION_MILLIS.
    • state.distanceFraction représente la distance parcourue par l'utilisateur vers le bas, allant de 0f (aucune traction) à 1f (traction complète).
    • Le modificateur graphicsLayer modifie l'échelle et la transparence.

Résultat

Cette vidéo montre l'indicateur personnalisé du code précédent :

Figure 3. Implémentation d'un geste "Tirer pour actualiser" avec un indicateur personnalisé.

Ressources supplémentaires