Le composant SwipeToDismissBox permet à un utilisateur d'ignorer ou de mettre à jour un élément en le balayant vers la gauche ou vers la droite.
Surface d'API
Utilisez le composable SwipeToDismissBox pour implémenter des actions déclenchées par des gestes de balayage. Voici les principaux paramètres :
state: étatSwipeToDismissBoxStatecréé pour stocker la valeur produite par les calculs sur l'élément de balayage, qui déclenche des événements lorsqu'il est produit.backgroundContent: composable personnalisable affiché derrière le contenu de l'élément, qui est révélé lorsque l'utilisateur balaie l'écran.
Exemple de base : mettre à jour ou ignorer en balayant l'écran
Les extraits de cet exemple montrent une implémentation de balayage qui met à jour l'élément lorsqu'il est balayé du début à la fin, ou qui le supprime lorsqu'il est balayé de la fin au début.
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( painter = rememberVectorPainter(if (todoItem.isItemDone) AppIcons.CheckBox else AppIcons.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( painter = rememberVectorPainter(AppIcons.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
swipeToDismissBoxStategère l'état du composant. Il déclenche le rappelconfirmValueChangeune 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é du début à la fin, il appelle le lambda
onToggleDone, en transmettant l'todoItemactuel. Cela correspond à la mise à jour de l'élément de la liste de tâches. - Si l'élément est balayé de la fin vers le début, il appelle le lambda
onRemoveen transmettant l'élémenttodoItemactuel. Cela correspond à la suppression de l'élément de la liste de tâches. it != StartToEnd: cette ligne renvoietruesi la direction du balayage n'est pasStartToEnd, etfalsedans le cas contraire. Renvoyerfalseempêche leSwipeToDismissBoxde disparaître immédiatement après un balayage "marquer comme terminé", ce qui permet d'afficher une confirmation visuelle ou une animation.
- Si l'élément est balayé du début à la fin, il appelle le lambda
SwipeToDismissBoxpermet d'activer les interactions de balayage horizontal sur chaque élément. Au repos, il affiche le contenu interne du composant, mais lorsqu'un utilisateur commence à balayer l'écran, le contenu est déplacé et lebackgroundContents'affiche. Le contenu normal et lebackgroundContentobtiennent les contraintes complètes du conteneur parent pour s'afficher. Lecontentest dessiné au-dessus de labackgroundContent. Dans ce cas :backgroundContentest implémenté en tant queIconavec une couleur d'arrière-plan basée surSwipeToDismissBoxValue:Bluelors d'un balayage versStartToEnd: cocher ou décocher une tâche à faire.Redlors du balayage deEndToStart: suppression d'une tâche.- Rien ne s'affiche en arrière-plan pour
Settled. Lorsque l'élément n'est pas balayé, rien ne s'affiche en arrière-plan. - De même, le
Iconqui s'affiche s'adapte à la direction du balayage : StartToEndaffiche une icôneCheckBoxlorsque la tâche est terminée et une icôneCheckBoxOutlineBlanklorsqu'elle ne l'est pas.EndToStartaffiche une icôneDelete.
@Composable 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é à cette liste ou en est supprimé, Compose recompose les parties de l'UI qui en dépendent.- Dans
mutableStateListOf(), quatre objetsTodoItemsont initialisés avec leurs descriptions respectives : "Payer les factures", "Faire les courses", "Aller à la salle de sport" et "Dîner".
- Dans
LazyColumnaffiche une liste à défilement vertical detodoItems.onToggleDone = { todoItem -> ... }est une fonction de rappel appelée depuisTodoListItemlorsque l'utilisateur marque un objet comme terminé. Elle met à jour la propriétéisItemDonedetodoItem. CommetodoItemsest 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. Elle supprime l'élémenttodoItemspécifique de la listetodoItems. Cela entraîne également une recomposition, et l'élément est supprimé de la liste affichée.- Un modificateur
animateItemest appliqué à chaqueTodoListItemafin que leplacementSpecdu 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 à partir des extraits précédents :
Consultez le fichier source GitHub pour obtenir l'exemple de code complet.
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( painter = rememberVectorPainter(if (todoItem.isItemDone) AppIcons.CheckBox else AppIcons.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( painter = rememberVectorPainter(AppIcons.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
drawBehinddessine directement dans le canevas derrière le contenu du composableIcon.drawRect()dessine un rectangle sur le canevas et remplit toutes les limites du champ d'application du dessin avec leColorspécifié.
- Lors du balayage, la couleur d'arrière-plan de l'élément change de manière fluide à l'aide de
lerp.- Pour un balayage depuis
StartToEnd, la couleur d'arrière-plan passe progressivement du gris clair au bleu. - Pour un balayage depuis
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 depuis
OutlinedCardajoute une séparation visuelle subtile entre les éléments de la 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 connaître les points clés de ce code, consultez la section Points clés d'une section précédente, qui décrit un extrait de code identique.
Résultat
La vidéo suivante montre la fonctionnalité avancée avec une couleur d'arrière-plan animée :
Consultez le fichier source GitHub pour obtenir l'exemple de code complet.