Komponent SwipeToDismissBox umożliwia użytkownikowi odrzucenie lub zaktualizowanie elementu przez przesunięcie go w lewo lub w prawo.
Interfejs API
Użyj funkcji kompozycyjnej SwipeToDismissBox, aby zaimplementować działania wywoływane gestami przesuwania. Najważniejsze parametry:
state: stanSwipeToDismissBoxStateutworzony do przechowywania wartości wygenerowanej przez obliczenia dotyczące elementu przesunięcia, który po wygenerowaniu wywołuje zdarzenia.backgroundContent: dostosowywany element kompozycyjny wyświetlany za treścią elementu, który jest widoczny po przesunięciu treści.
Podstawowy przykład: aktualizowanie lub odrzucanie po przesunięciu palcem
Fragmenty kodu w tym przykładzie pokazują implementację przesunięcia, która aktualizuje element po przesunięciu od początku do końca lub odrzuca element po przesunięciu 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( 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.") } ) } }
Najważniejsze informacje o kodzie
swipeToDismissBoxStatezarządza stanem komponentu. Po zakończeniu interakcji z elementem wywołuje wywołanie zwrotneconfirmValueChange. Treść wywołania zwrotnego obsługuje różne możliwe działania. Wywołanie zwrotne zwraca wartość logiczną, która informuje komponent, czy powinien wyświetlić animację zamknięcia. W takim przypadku:- Jeśli element zostanie przesunięty od początku do końca, wywołuje funkcję lambda
onToggleDone, przekazując bieżący elementtodoItem. Odpowiada to aktualizacji zadania. - Jeśli element zostanie przesunięty od końca do początku, wywołuje funkcję lambda
onRemove, przekazując bieżący elementtodoItem. Odpowiada to usunięciu elementu listy zadań. it != StartToEnd: ten wiersz zwraca wartośćtrue, jeśli kierunek przesunięcia nie jestStartToEnd, a w przeciwnym razie zwraca wartośćfalse. Zwrócenie wartościfalsezapobiega natychmiastowemu zniknięciu elementuSwipeToDismissBoxpo przesunięciu palcem w celu oznaczenia jako gotowe, co umożliwia wyświetlenie potwierdzenia wizualnego lub animacji.
- Jeśli element zostanie przesunięty od początku do końca, wywołuje funkcję lambda
SwipeToDismissBoxumożliwia przesuwanie każdego elementu w poziomie. W stanie spoczynku pokazuje wewnętrzną zawartość komponentu, ale gdy użytkownik zacznie przesuwać palcem, zawartość zostanie odsunięta i pojawi siębackgroundContent. Zarówno zwykłe treści, jak ibackgroundContentsą renderowane z uwzględnieniem wszystkich ograniczeń kontenera nadrzędnego. Elementcontentjest rysowany nad elementembackgroundContent. W takim przypadku:backgroundContentjest zaimplementowany jakoIconz kolorem tła opartym naSwipeToDismissBoxValue:Bluepodczas przesuwaniaStartToEnd– przełączanie zadania do wykonania.Redpodczas przesuwaniaEndToStart– usuwanie zadania.- W tle nie jest wyświetlana żadna treść dla
Settled– gdy element nie jest przesuwany, w tle nie jest wyświetlana żadna treść. - Podobnie wyświetlany
Icondostosowuje się do kierunku przesunięcia: StartToEndwyświetla ikonęCheckBox, gdy zadanie jest wykonane, i ikonęCheckBoxOutlineBlank, gdy nie jest wykonane.EndToStartwyświetla ikonęDelete.
@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() ) } } }
Najważniejsze informacje o kodzie
mutableStateListOf(...)tworzy listę obserwowalną, która może zawierać obiektyTodoItem. Gdy element zostanie dodany do tej listy lub z niej usunięty, Compose ponownie skomponuje te części interfejsu, które od niej zależą.- W metodzie
mutableStateListOf()inicjowane są 4 obiektyTodoItemz odpowiednimi opisami: „Pay bills”, „Buy groceries”, „Go to gym” i „Get dinner”.
- W metodzie
LazyColumnwyświetla przewijaną w pionie listętodoItems.onToggleDone = { todoItem -> ... }to funkcja wywołania zwrotnego wywoływana zTodoListItem, gdy użytkownik oznaczy obiekt jako gotowy. Aktualizuje właściwośćisItemDoneelementutodoItem. PonieważtodoItemsjestmutableStateListOf, ta zmiana powoduje rekompozycję, która aktualizuje interfejs.onRemove = { todoItem -> ... }to funkcja wywołania zwrotnego, która jest aktywowana, gdy użytkownik usunie element. Usuwa określony elementtodoItemz listytodoItems. Spowoduje to też rekompozycję, a element zostanie usunięty z wyświetlanej listy.- Do każdego elementu
TodoListItemstosowany jest modyfikatoranimateItem, dzięki czemu po odrzuceniu elementu wywoływana jest funkcjaplacementSpecmodyfikatora. Spowoduje to animację usunięcia elementu oraz zmiany kolejności innych elementów na liście.
Wynik
Poniższy film pokazuje podstawową funkcję przesuwania w celu zamknięcia z poprzednich fragmentów kodu:
Pełny przykładowy kod znajdziesz w pliku źródłowym na GitHubie.
Przykład zaawansowany: animowanie koloru tła podczas przesuwania
Poniższe fragmenty kodu pokazują, jak uwzględnić 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( 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.") } ) } } }
Najważniejsze informacje o kodzie
drawBehindrysuje bezpośrednio na obszarze roboczym za zawartością funkcji kompozycyjnejIcon.drawRect()rysuje prostokąt na obszarze roboczym i wypełnia cały zakres rysowania określonym elementemColor.
- Podczas przesuwania kolor tła elementu płynnie się zmienia, używając
lerp.- W przypadku przesunięcia od
StartToEndkolor tła stopniowo zmienia się z jasnoszarego na niebieski. - W przypadku przesunięcia od
EndToStartkolor tła stopniowo zmienia się z jasnoszarego na czerwony. - Stopień przejścia z jednego koloru do drugiego jest określany przez
swipeToDismissBoxState.progress.
- W przypadku przesunięcia od
OutlinedCarddodaje subtelne wizualne rozdzielenie elementów 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 poprzednim rozdziale, w którym opisano identyczny fragment kodu.
Wynik
Ten film przedstawia zaawansowane funkcje z animowanym kolorem tła:
Pełny przykładowy kod znajdziesz w pliku źródłowym na GitHubie.