Faire glisser pour actualiser

Le composant "glisser vers le bas 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 le geste "glisser vers le bas pour actualiser", qui sert de conteneur pour votre contenu à faire défiler. 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 lorsque l'utilisateur glisse vers le bas pour actualiser.

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 illustre l'implémentation de base de la fonctionnalité "glisser vers le bas pour actualiser" à partir du code précédent :

Figure 1. Implémentation de base de la fonctionnalité "glisser vers le bas pour actualiser" 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 via les 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 la fonctionnalité "glisser vers le bas pour actualiser" avec un indicateur de couleur :

Figure 2. Implémentation de la fonctionnalité "glisser vers le bas pour actualiser" avec un style personnalisé.

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

Vous pouvez créer des indicateurs personnalisés complexes en exploitant les composables et les animations existants.Cet extrait montre comment créer un indicateur entièrement personnalisé dans votre implémentation de la fonctionnalité Glisser vers le bas pour actualiser :

@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.pullToRefresh(
            state = state,
            isRefreshing = isRefreshing,
            threshold = PositionalThreshold,
            onRefresh = {

            }
        ),
        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 afin que vous puissiez transmettre la même instance à PullToRefreshBox et à pullToRefreshModifier.
  • L'exemple utilise la couleur du conteneur et le seuil de position de la classe PullToRefreshDefaults. De cette façon, vous pouvez réutiliser le comportement et le style par défaut de la bibliothèque Material, tout en ne personnalisant que les éléments qui vous intéressent.
  • MyCustomIndicator utilise Crossfade pour passer d'une icône de cloud à un CircularProgressIndicator. L'icône de nuage s'agrandit lorsque l'utilisateur tire vers le bas, puis se transforme en CircularProgressIndicator lorsque l'action d'actualisation commence.
    • targetState utilise isRefreshing pour déterminer l'état à afficher (l'icône de cloud 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 sur laquelle l'utilisateur a tiré vers le bas, de 0f (aucune action) à 1f (tiré au maximum).
    • 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 de la fonctionnalité "Glisser vers le bas pour actualiser" avec un indicateur personnalisé.

Ressources supplémentaires