Komponent SwipeToDismissBox
pozwala użytkownikowi odrzucić lub zaktualizować element, przesuwając go w lewo lub w prawo.
Interfejs API
Aby zaimplementować działania wywoływane przez gesty przesuwania, użyj komponentu SwipeToDismissBox
. Kluczowe parametry:
state
: stanSwipeToDismissBoxState
utworzony w celu przechowywania wartości wygenerowanej przez obliczenia dotyczące elementu przesuwania, który uruchamia zdarzenia po wygenerowaniu.backgroundContent
: konfigurowalny element kompozycyjny wyświetlany za treścią, który ujawnia się po przesunięciu treści.
Przykład podstawowy: aktualizacja lub zamknięcie po przesunięciu
W tym przykładzie fragmenty kodu pokazują implementację przesuwania, która aktualizuje element, gdy przesuniesz go od początku do końca, lub zamyka go, gdy przesuniesz go od końca do początku.
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.") } ) } }
Najważniejsze informacje o kodzie
swipeToDismissBoxState
zarządza stanem komponentu. Po zakończeniu interakcji z elementem wywołuje on funkcjęconfirmValueChange
. Treść wywołania zwrotnego obsługuje różne możliwe działania. Wywołanie zwrotne zwraca wartość logiczną, która informuje komponent, czy ma wyświetlić animację zamykania. W tym przypadku:- Jeśli element jest przesuwany od początku do końca, wywołuje funkcję
onToggleDone
lambda, przekazując bieżącą wartośćtodoItem
. Odpowiada to aktualizowaniu elementu listy zadań. - Jeśli element jest przesuwany od końca do początku, wywołuje funkcję
onRemove
lambda, przekazując bieżącą wartośćtodoItem
. Odpowiada to usunięciu zadania. it != StartToEnd
: ta linijka zwraca wartośćtrue
, jeśli kierunek przesunięcia nie jestStartToEnd
, a w przeciwnym razie zwraca wartośćfalse
. Zwracaniefalse
zapobiega natychmiastowemu zniknięciuSwipeToDismissBox
po przesunięciu palcem, co umożliwia wizualne potwierdzenie lub animację.
- Jeśli element jest przesuwany od początku do końca, wywołuje funkcję
SwipeToDismissBox
umożliwia przesuwanie elementów poziomo. W przypadku Pinteresta pokazuje ona wewnętrzną zawartość komponentu, ale gdy użytkownik zacznie przesuwać palcem, treść zostanie usunięta i pojawi siębackgroundContent
. Zarówno normalna zawartość, jak ibackgroundContent
mają pełne ograniczenia kontenera nadrzędnego, w którym są renderowane.content
jest narysowana na wierzchubackgroundContent
. W tym przypadku:backgroundContent
jest implementowany jakoIcon
z kolorem tła opartym naSwipeToDismissBoxValue
:Blue
podczas przesuwaniaStartToEnd
– włączanie i wyłączanie elementu listy zadań.Red
podczas przesuwaniaEndToStart
– usuwanie zadania.- W przypadku
Settled
tło nie jest wyświetlane – gdy element nie jest przesuwany, tło nie jest wyświetlane. - Podobnie wyświetlana
Icon
dostosowuje się do kierunku przesuwania: StartToEnd
wyświetla ikonęCheckBox
, gdy zadanie jest wykonane, i ikonęCheckBoxOutlineBlank
, gdy nie jest wykonane.EndToStart
wyświetla ikonę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() ) } } }
Najważniejsze informacje o kodzie
mutableStateListOf(...)
tworzy obserwowalną listę, która może zawierać obiektyTodoItem
. Gdy element zostanie dodany do tej listy lub z niej usunięty, Compose ponownie utworzy te części interfejsu, które na nim polegają.- Wewnątrz
mutableStateListOf()
inicjowane są 4 obiektyTodoItem
z odpowiednimi opisami: „Opłacanie rachunków”, „Zakupy spożywcze”, „Chodzenie na siłownię” i „Kolacja”.
- Wewnątrz
LazyColumn
wyświetla listętodoItems
przewijaną w pionie.onToggleDone = { todoItem -> ... }
to funkcja wywołania zwrotnego wywoływana z poziomuTodoListItem
, gdy użytkownik zaznaczy obiekt jako gotowy. Zmień właściwośćisItemDone
w komponencietodoItem
. PonieważtodoItems
jestmutableStateListOf
, ta zmiana powoduje ponowne skompilowanie i zaktualizowanie interfejsu.onRemove = { todoItem -> ... }
to funkcja wywołania zwrotnego, która jest wywoływana, gdy użytkownik usunie element. Usuwa określony elementtodoItem
z listytodoItems
. Spowoduje to również ponowne złożenie listy, a element zostanie usunięty z wyświetlanej listy.- Modyfikator
animateItem
jest stosowany do każdego elementuTodoListItem
, aby wywołać funkcjęplacementSpec
modyfikatora po odrzuceniu elementu. W tym celu animujesz usunięcie elementu oraz zmianę kolejności innych elementów na liście.
Wynik
Ten film pokazuje podstawową funkcję przesuwania, aby zamknąć, z poprzednich fragmentów kodu:
Pełny przykładowy kod znajdziesz w pliku źródłowym na GitHubie.
Przykład zaawansowany: animacja koloru tła podczas przesuwania
Poniższe fragmenty kodu pokazują, jak zastosować próg pozycji, aby animować kolor tła elementu podczas przesuwania.
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.") } ) } } }
Najważniejsze informacje o kodzie
drawBehind
rysuje bezpośrednio na płótnie za treścią elementuIcon
.drawRect()
rysuje prostokąt na płótnie i wypełnia cały zakres rysunku określonymColor
.
- Podczas przesuwania kolor tła elementu zmienia się płynnie za pomocą funkcji
lerp
.- W przypadku przesunięcia z poziomu
StartToEnd
kolor tła stopniowo zmienia się z jasnego szarego na niebieski. - W przypadku przesunięcia z
EndToStart
kolor tła stopniowo zmienia się z jasnego szarego na czerwony. - Wielkość przejścia z jednego koloru na następny określa parametr
swipeToDismissBoxState.progress
.
- W przypadku przesunięcia z poziomu
OutlinedCard
dodaje subtelne wizualne oddzielenie między elementami listy.
@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() ) } } }
Najważniejsze informacje o kodzie
- Najważniejsze informacje o tym kodzie znajdziesz w sekcji Najważniejsze informacje w poprzedniej sekcji, która zawiera identyczny fragment kodu.
Wynik
Ten film pokazuje zaawansowane funkcje z animowanym tłem:
Pełny przykładowy kod znajdziesz w pliku źródłowym na GitHubie.