El componente SwipeToDismissBox permite que un usuario descarte o actualice un elemento deslizándolo hacia la izquierda o la derecha.
Plataforma de la API
Usa el elemento componible SwipeToDismissBox para implementar acciones que se activan con gestos de deslizamiento. Entre los parámetros clave, se incluyen los siguientes:
state: Es el estadoSwipeToDismissBoxStatecreado para almacenar el valor que producen los cálculos en el elemento de deslizamiento, que activa eventos cuando se produce.backgroundContent: Es un elemento componible personalizable que se muestra detrás del contenido del elemento y que se revela cuando se desliza el contenido.
Ejemplo básico: Actualiza o descarta con un deslizamiento
Los fragmentos de este ejemplo muestran una implementación de deslizamiento que actualiza el elemento cuando se desliza de un extremo al otro o lo descarta cuando se desliza de un extremo al otro.
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.") } ) } }
Puntos clave sobre el código
swipeToDismissBoxStateadministra el estado del componente. Activa la devolución de llamadaconfirmValueChangeuna vez que se completa la interacción con el elemento. El cuerpo de la devolución de llamada controla las diferentes acciones posibles. La devolución de llamada muestra un valor booleano que le indica al componente si debe mostrar una animación de descarte. En este caso:- Si se desliza el elemento de un extremo al otro, llama a la lambda 
onToggleDoney pasa eltodoItemactual. Esto corresponde a la actualización del elemento de tareas pendientes. - Si se desliza el elemento de un extremo al otro, llama a la lambda 
onRemovey pasa eltodoItemactual. Esto corresponde a borrar el elemento de tareas pendientes. it != StartToEnd: Esta línea muestratruesi la dirección del deslizamiento no esStartToEndyfalsede lo contrario. Devolverfalseevita queSwipeToDismissBoxdesaparezca de inmediato después de un deslizamiento de "activar/desactivar", lo que permite una confirmación o animación visual.
- Si se desliza el elemento de un extremo al otro, llama a la lambda 
 SwipeToDismissBoxhabilita interacciones de deslizamiento horizontal en cada elemento. En reposo, muestra el contenido interno del componente, pero cuando un usuario comienza a deslizar el dedo, el contenido se aleja y aparece elbackgroundContent. Tanto el contenido normal como elbackgroundContentobtienen las restricciones completas del contenedor superior para renderizarse. Elcontentse dibuja sobre elbackgroundContent. En este caso:backgroundContentse implementa como unIconcon un color de fondo basado enSwipeToDismissBoxValue:Bluecuando se deslizaStartToEnd: Activa o desactiva una tarea pendiente.Redcuando se deslizaEndToStart: Borra una tarea pendiente.- No se muestra nada en segundo plano para 
Settled; cuando no se desliza el elemento, no se muestra nada en segundo plano. - Del mismo modo, el 
Iconque se muestra se adapta a la dirección del deslizamiento: StartToEndmuestra un ícono deCheckBoxcuando se completa la tarea y un ícono deCheckBoxOutlineBlankcuando no se completa.EndToStartmuestra un íconoDelete.
@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() ) } } }
Puntos clave sobre el código
mutableStateListOf(...)crea una lista observable que puede contener objetosTodoItem. Cuando se agrega o quita un elemento de esta lista, Compose recompone las partes de la IU que dependen de él.- Dentro de 
mutableStateListOf(), se inicializan cuatro objetosTodoItemcon sus respectivas descripciones: “Pagar facturas”, “Comprar comestibles”, “Ir al gimnasio” y “Comer”. 
- Dentro de 
 LazyColumnmuestra una lista detodoItemscon desplazamiento vertical.onToggleDone = { todoItem -> ... }es una función de devolución de llamada que se invoca desdeTodoListItemcuando el usuario marca un objeto como terminado. Actualiza la propiedadisItemDonedetodoItem. ComotodoItemses unmutableStateListOf, este cambio activa una recomposición y actualiza la IU.onRemove = { todoItem -> ... }es una función de devolución de llamada que se activa cuando el usuario quita el elemento. Quita eltodoItemespecífico de la listatodoItems. Esto también causa una recomposición, y el elemento se quitará de la lista que se muestra.- Se aplica un modificador 
animateItema cadaTodoListItempara que se llame aplacementSpecdel modificador cuando se descarte el elemento. Esto anima la eliminación del elemento, así como la reorganización de otros elementos de la lista. 
Resultado
En el siguiente video, se muestra la funcionalidad básica de deslizar para descartar de los fragmentos anteriores:
Consulta el archivo fuente de GitHub para ver el código de muestra completo.
Ejemplo avanzado: Anima el color de fondo al deslizar el dedo
En los siguientes fragmentos, se muestra cómo incorporar un umbral de posición para animar el color de fondo de un elemento cuando se desliza el dedo.
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.") } ) } } }
Puntos clave sobre el código
drawBehinddibuja directamente en el lienzo detrás del contenido del elemento componibleIcon.drawRect()dibuja un rectángulo en el lienzo y completa todos los límites del alcance de dibujo con elColorespecificado.
- Cuando se desliza el dedo, el color de fondo del elemento cambia de forma fluida con 
lerp.- Para un deslizamiento desde 
StartToEnd, el color de fondo cambia gradualmente de gris claro a azul. - Para un deslizamiento desde 
EndToStart, el color de fondo cambia gradualmente de gris claro a rojo. - La cantidad de transición de un color al siguiente se determina mediante 
swipeToDismissBoxState.progress. 
 - Para un deslizamiento desde 
 OutlinedCardagrega una separación visual sutil entre los elementos de la lista.
@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() ) } } }
Puntos clave sobre el código
- Para obtener información sobre los puntos clave de este código, consulta Puntos clave en una sección anterior, que describe un fragmento de código idéntico.
 
Resultado
En el siguiente video, se muestra la funcionalidad avanzada con color de fondo animado:
Consulta el archivo fuente de GitHub para ver el código de muestra completo.