Faire glisser pour actualiser

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

Surface de l'API

Utilisez le composable PullToRefreshBox pour implémenter le rafraîchissement par glissement, qui sert de conteneur à votre contenu à faire défiler. Les principaux paramètres 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 dessiné lors de l'actualisation par balayage.

Exemple de base

Cet extrait illustre 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 élément 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 à faire défiler.

Résultat

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

Figure 1 : Implémentation de base de la fonctionnalité de balayage pour actualiser 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 avec le paramètre indicator.

Résultat

Cette vidéo montre une implémentation de la fonctionnalité de rafraîchissement par glissement avec un indicateur de couleur:

Figure 2. Implémentation du rafraîchissement par balayage 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é de rafraîchissement par glissement:

@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'instance PullToRefreshState a été extraite. Par conséquent, la même instance peut être transmise à la fois à PullToRefreshBox et à pullToRefreshModifier.
  • La couleur du conteneur et le seuil de position sont utilisés à partir de la classe PullToRefreshDefaults. Vous pouvez ainsi 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 effectuer la transition entre une icône de nuage et un CircularProgressIndicator. L'icône du nuage se met à l'échelle lorsque l'utilisateur tire et passe à CircularProgressIndicator lorsque l'action d'actualisation commence.
    • targetState utilise isRefreshing pour déterminer l'état à afficher (l'icône 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 de défilement de l'utilisateur, allant de 0f (pas de défilement) à 1f (défilement complet).
    • 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é de balayage pour actualiser avec un indicateur personnalisé.

Ressources supplémentaires