Le composant SwipeToDismissBox
permet à un utilisateur d'ignorer ou de mettre à jour un élément en le balayant vers la gauche ou la droite.
Surface de l'API
Utilisez le composable SwipeToDismissBox
pour implémenter des actions déclenchées par des gestes de balayage. Voici les principaux paramètres:
state
: étatSwipeToDismissBoxState
créé pour stocker la valeur générée par les calculs sur l'élément de balayage, qui déclenche des événements lorsqu'il est généré.backgroundContent
: composable personnalisable affiché derrière le contenu de l'élément, qui s'affiche lorsque le contenu est balayé.
Exemple de base: Mise à jour ou refus en balayant l'écran
Les extraits de code de cet exemple montrent une implémentation de balayage qui met à jour l'élément lorsqu'il est balayé de gauche à droite ou le ferme lorsqu'il est balayé de droite à gauche.
data class TodoItem( val itemDescription: String, var isItemDone: Boolean = false )
@Composable fun TodoListItem( todoItem: TodoItem, onToggleDone: (TodoItem) -> Unit, onRemove: (TodoItem) -> Unit, modifier: Modifier = Modifier, ) { val swipeToDismissBoxState = rememberSwipeToDismissBoxState( confirmValueChange = { if (it == StartToEnd) onToggleDone(todoItem) else if (it == EndToStart) onRemove(todoItem) // Reset item when toggling done status it != StartToEnd } ) SwipeToDismissBox( state = swipeToDismissBoxState, modifier = modifier.fillMaxSize(), backgroundContent = { when (swipeToDismissBoxState.dismissDirection) { StartToEnd -> { Icon( if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.CheckBoxOutlineBlank, contentDescription = if (todoItem.isItemDone) "Done" else "Not done", modifier = Modifier .fillMaxSize() .background(Color.Blue) .wrapContentSize(Alignment.CenterStart) .padding(12.dp), tint = Color.White ) } EndToStart -> { Icon( imageVector = Icons.Default.Delete, contentDescription = "Remove item", modifier = Modifier .fillMaxSize() .background(Color.Red) .wrapContentSize(Alignment.CenterEnd) .padding(12.dp), tint = Color.White ) } Settled -> {} } } ) { ListItem( headlineContent = { Text(todoItem.itemDescription) }, supportingContent = { Text("swipe me to update or remove.") } ) } }
Points clés concernant le code
swipeToDismissBoxState
gère l'état du composant. Il déclenche le rappelconfirmValueChange
une fois l'interaction avec l'élément terminée. Le corps du rappel gère les différentes actions possibles. Le rappel renvoie une valeur booléenne qui indique au composant s'il doit afficher une animation de fermeture. Dans ce cas :- Si l'élément est balayé de gauche à droite, il appelle le lambda
onToggleDone
en transmettant letodoItem
actuel. Cela correspond à la mise à jour de la tâche. - Si l'élément est balayé de la fin au début, il appelle le lambda
onRemove
, en transmettant letodoItem
actuel. Cela correspond à la suppression de l'élément de la liste de tâches. it != StartToEnd
: cette ligne renvoietrue
si la direction du balayage n'est pasStartToEnd
, etfalse
dans le cas contraire. Le retour defalse
empêche laSwipeToDismissBox
de disparaître immédiatement après un balayage "Activer/Désactiver", ce qui permet une confirmation ou une animation visuelle.
- Si l'élément est balayé de gauche à droite, il appelle le lambda
SwipeToDismissBox
permet les interactions de balayage horizontal sur chaque élément. En mode veille, il affiche le contenu interne du composant, mais lorsqu'un utilisateur commence à balayer l'écran, le contenu est déplacé etbackgroundContent
s'affiche. Le contenu normal et lebackgroundContent
obtiennent toutes les contraintes du conteneur parent pour s'afficher. Lecontent
est dessiné au-dessus dubackgroundContent
. Dans ce cas :backgroundContent
est implémenté en tant queIcon
avec une couleur d'arrière-plan basée surSwipeToDismissBoxValue
:Blue
lors du balayageStartToEnd
: activation/désactivation d'un élément de la liste de tâches.Red
lorsque vous balayez l'écranEndToStart
: suppression d'un élément de la liste de tâches.- Rien n'est affiché en arrière-plan pour
Settled
. Lorsque l'élément n'est pas balayé, rien n'est affiché en arrière-plan. - De même, le
Icon
affiché s'adapte à la direction du balayage: StartToEnd
affiche une icôneCheckBox
lorsque la tâche est terminée et une icôneCheckBoxOutlineBlank
lorsqu'elle ne l'est pas.EndToStart
affiche une icôneDelete
.
@Composable private fun SwipeItemExample() { val todoItems = remember { mutableStateListOf( TodoItem("Pay bills"), TodoItem("Buy groceries"), TodoItem("Go to gym"), TodoItem("Get dinner") ) } LazyColumn { items( items = todoItems, key = { it.itemDescription } ) { todoItem -> TodoListItem( todoItem = todoItem, onToggleDone = { todoItem -> todoItem.isItemDone = !todoItem.isItemDone }, onRemove = { todoItem -> todoItems -= todoItem }, modifier = Modifier.animateItem() ) } } }
Points clés concernant le code
mutableStateListOf(...)
crée une liste observable pouvant contenir des objetsTodoItem
. Lorsqu'un élément est ajouté ou supprimé de cette liste, Compose recompose les parties de l'UI qui en dépendent.- Dans
mutableStateListOf()
, quatre objetsTodoItem
sont initialisés avec leurs descriptions respectives: "Payer les factures", "Acheter des produits alimentaires", "Aller à la salle de sport" et "Dîner".
- Dans
LazyColumn
affiche une liste à défilement vertical detodoItems
.onToggleDone = { todoItem -> ... }
est une fonction de rappel appelée depuisTodoListItem
lorsque l'utilisateur marque un objet comme terminé. Il met à jour la propriétéisItemDone
detodoItem
. Étant donné quetodoItems
est unmutableStateListOf
, cette modification déclenche une recomposition, ce qui met à jour l'UI.onRemove = { todoItem -> ... }
est une fonction de rappel déclenchée lorsque l'utilisateur supprime l'élément. Il supprime l'todoItem
spécifique de la listetodoItems
. Une recomposition est également effectuée, et l'élément est supprimé de la liste affichée.- Un modificateur
animateItem
est appliqué à chaqueTodoListItem
afin que leplacementSpec
du modificateur soit appelé lorsque l'élément a été ignoré. Cela anime la suppression de l'élément, ainsi que la réorganisation des autres éléments de la liste.
Résultat
La vidéo suivante illustre la fonctionnalité de base de balayage pour ignorer des extraits précédents:
Pour obtenir l'exemple de code complet, consultez le fichier source GitHub.
Exemple avancé: animer la couleur d'arrière-plan lors d'un balayage
Les extraits de code suivants montrent comment intégrer un seuil de position pour animer la couleur d'arrière-plan d'un élément lors d'un balayage.
data class TodoItem( val itemDescription: String, var isItemDone: Boolean = false )
@Composable fun TodoListItemWithAnimation( todoItem: TodoItem, onToggleDone: (TodoItem) -> Unit, onRemove: (TodoItem) -> Unit, modifier: Modifier = Modifier, ) { val swipeToDismissBoxState = rememberSwipeToDismissBoxState( confirmValueChange = { if (it == StartToEnd) onToggleDone(todoItem) else if (it == EndToStart) onRemove(todoItem) // Reset item when toggling done status it != StartToEnd } ) SwipeToDismissBox( state = swipeToDismissBoxState, modifier = modifier.fillMaxSize(), backgroundContent = { when (swipeToDismissBoxState.dismissDirection) { StartToEnd -> { Icon( if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.CheckBoxOutlineBlank, contentDescription = if (todoItem.isItemDone) "Done" else "Not done", modifier = Modifier .fillMaxSize() .drawBehind { drawRect(lerp(Color.LightGray, Color.Blue, swipeToDismissBoxState.progress)) } .wrapContentSize(Alignment.CenterStart) .padding(12.dp), tint = Color.White ) } EndToStart -> { Icon( imageVector = Icons.Default.Delete, contentDescription = "Remove item", modifier = Modifier .fillMaxSize() .background(lerp(Color.LightGray, Color.Red, swipeToDismissBoxState.progress)) .wrapContentSize(Alignment.CenterEnd) .padding(12.dp), tint = Color.White ) } Settled -> {} } } ) { OutlinedCard(shape = RectangleShape) { ListItem( headlineContent = { Text(todoItem.itemDescription) }, supportingContent = { Text("swipe me to update or remove.") } ) } } }
Points clés concernant le code
drawBehind
dessine directement dans le canevas derrière le contenu du composableIcon
.drawRect()
dessine un rectangle sur le canevas et remplit l'ensemble des limites du champ d'application du dessin avec laColor
spécifiée.
- Lorsque vous balayez l'écran, la couleur d'arrière-plan de l'élément passe en douceur à l'aide de
lerp
.- Pour un balayage à partir de
StartToEnd
, la couleur d'arrière-plan passe progressivement du gris clair au bleu. - Pour un balayage à partir de
EndToStart
, la couleur d'arrière-plan passe progressivement du gris clair au rouge. - La quantité de transition d'une couleur à l'autre est déterminée par
swipeToDismissBoxState.progress
.
- Pour un balayage à partir de
OutlinedCard
ajoute une séparation visuelle subtile entre les éléments de liste.
@Composable private fun SwipeItemWithAnimationExample() { val todoItems = remember { mutableStateListOf( TodoItem("Pay bills"), TodoItem("Buy groceries"), TodoItem("Go to gym"), TodoItem("Get dinner") ) } LazyColumn { items( items = todoItems, key = { it.itemDescription } ) { todoItem -> TodoListItemWithAnimation( todoItem = todoItem, onToggleDone = { todoItem -> todoItem.isItemDone = !todoItem.isItemDone }, onRemove = { todoItem -> todoItems -= todoItem }, modifier = Modifier.animateItem() ) } } }
Points clés concernant le code
- Pour en savoir plus sur ce code, consultez les points clés d'une section précédente, qui décrit un extrait de code identique.
Résultat
La vidéo suivante présente les fonctionnalités avancées avec une couleur d'arrière-plan animée:
Pour obtenir l'exemple de code complet, consultez le fichier source GitHub.