Компонент SwipeToDismissBox позволяет пользователю закрыть или обновить элемент, проведя по нему пальцем влево или вправо.
API поверхность
 Используйте SwipeToDismissBox composable для реализации действий, которые запускаются жестами смахивания. Ключевые параметры включают:
-  
state: СостояниеSwipeToDismissBoxState, созданное для хранения значения, полученного в результате вычислений для элемента смахивания, которое запускает события при создании. -  
backgroundContent: настраиваемый компонуемый элемент, отображаемый позади содержимого элемента, который становится виден при пролистывании содержимого. 
Простой пример: обновление или удаление при смахивании
Фрагменты в этом примере демонстрируют реализацию смахивания, которая либо обновляет элемент при смахивании от начала до конца, либо закрывает элемент при смахивании от конца до начала.
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.") } ) } }
Ключевые моменты кодекса
-  
swipeToDismissBoxStateуправляет состоянием компонента. Он запускает обратный вызовconfirmValueChangeпосле завершения взаимодействия с элементом. Тело обратного вызова обрабатывает различные возможные действия. Обратный вызов возвращает логическое значение, которое сообщает компоненту, следует ли отображать анимацию отклонения. В этом случае:-  Если элемент пролистывается от начала до конца, он вызывает лямбду 
onToggleDone, передавая текущийtodoItem. Это соответствует обновлению элемента todo. -  Если элемент смахивается с конца в начало, вызывается лямбда-функция 
onRemove, передающая текущийtodoItem. Это соответствует удалению элемента todo. -  
it != StartToEnd: Эта строка возвращаетtrueесли направление смахивания неStartToEnd, иfalseв противном случае. Возвращениеfalseпредотвращает немедленное исчезновениеSwipeToDismissBoxпосле смахивания «переключение выполнено», позволяя визуальное подтверждение или анимацию. 
 -  Если элемент пролистывается от начала до конца, он вызывает лямбду 
 -  
SwipeToDismissBoxпозволяет горизонтальное взаимодействие смахивания для каждого элемента. В состоянии покоя он показывает внутреннее содержимое компонента, но когда пользователь начинает смахивание, содержимое перемещается и появляетсяbackgroundContent. И обычное содержимое, иbackgroundContentполучают полные ограничения родительского контейнера для рендеринга.contentрисуется поверхbackgroundContent. В этом случае:-  
backgroundContentреализован какIconс фоновым цветом на основеSwipeToDismissBoxValue: -  
Blueпри смахиванииStartToEnd— переключение между задачами. -  
Redпри смахиванииEndToStart— удаление элемента списка дел. -  Для 
Settledничего не отображается на заднем плане — когда элемент не перемещается, на заднем плане ничего не отображается. -  Аналогично, отображаемый 
Iconадаптируется к направлению проведения пальцем: -  
StartToEndотображает значокCheckBox, когда задача выполнена, и значокCheckBoxOutlineBlank, когда задача не выполнена. -  
EndToStartотображает значокDelete. 
 -  
 
@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() ) } } }
Ключевые моменты кодекса
-  
mutableStateListOf(...)создает наблюдаемый список, который может содержать объектыTodoItem. Когда элемент добавляется или удаляется из этого списка, Compose перекомпоновывает части пользовательского интерфейса, которые зависят от него.-  Внутри 
mutableStateListOf()инициализируются четыре объектаTodoItemс соответствующими описаниями: «Оплатить счета», «Купить продукты», «Сходить в спортзал» и «Приготовить ужин». 
 -  Внутри 
 -  
LazyColumnотображает вертикально прокручиваемый списокtodoItems. -  
onToggleDone = { todoItem -> ... }— это функция обратного вызова, вызываемая изTodoListItem, когда пользователь отмечает объект как выполненный. Она обновляет свойствоisItemDoneдляtodoItem. ПосколькуtodoItems— этоmutableStateListOf, это изменение запускает перекомпозицию, обновляя пользовательский интерфейс. -  
onRemove = { todoItem -> ... }— это функция обратного вызова, которая активируется, когда пользователь удаляет элемент. Она удаляет конкретныйtodoItemиз спискаtodoItems. Это также вызывает перекомпозицию, и элемент будет удален из отображаемого списка. -  Модификатор 
animateItemприменяется к каждомуTodoListItem, так чтоplacementSpecмодификатора вызывается, когда элемент был отклонен. Это анимирует удаление элемента, а также переупорядочивание других элементов в списке. 
Результат
В следующем видео демонстрируется базовая функциональность смахивания для закрытия из предыдущих фрагментов:
Полный пример кода смотрите в исходном файле GitHub .
Расширенный пример: анимация цвета фона при смахивании
В следующих фрагментах показано, как использовать позиционный порог для анимации цвета фона элемента при проведении пальцем.
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.") } ) } } }
Ключевые моменты кодекса
-  
drawBehindрисует непосредственно на холсте за содержимым компонуемогоIcon.-  
drawRect()рисует прямоугольник на холсте и заполняет все границы области рисования указаннымColor. 
 -  
 -  При проведении пальцем цвет фона элемента плавно меняется с помощью 
lerp.-  При проведении пальцем от 
StartToEndцвет фона постепенно меняется со светло-серого на синий. -  При проведении пальцем от 
EndToStartцвет фона постепенно меняется со светло-серого на красный. -  Величина перехода от одного цвета к другому определяется параметром 
swipeToDismissBoxState.progress. 
 -  При проведении пальцем от 
 -  
OutlinedCardдобавляет тонкое визуальное разделение между элементами списка. 
@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() ) } } }
Ключевые моменты кодекса
- Основные положения этого кода см. в разделе «Основные положения» предыдущего раздела, в котором описывается идентичный фрагмент кода.
 
Результат
В следующем видео показаны расширенные функциональные возможности с анимированным фоновым цветом:
Полный пример кода смотрите в исходном файле GitHub .