Il componente SwipeToDismissBox consente a un utente di ignorare o aggiornare un elemento scorrendo verso sinistra o verso destra.
Piattaforma API
Utilizza il componibile SwipeToDismissBox per implementare le azioni attivate dai gesti di scorrimento. I parametri principali includono:
state: lo statoSwipeToDismissBoxStatecreato per archiviare il valore prodotto dai calcoli sull'elemento di scorrimento, che attiva gli eventi quando viene prodotto.backgroundContent: un componibile personalizzabile visualizzato dietro i contenuti dell'elemento che viene mostrato quando i contenuti vengono fatti scorrere.
Esempio di base: aggiornamento o chiusura con scorrimento
Gli snippet di questo esempio mostrano un'implementazione dello scorrimento che aggiorna l'elemento quando viene fatto scorrere dall'inizio alla fine o lo chiude quando viene fatto scorrere dalla fine all'inizio.
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.") } ) } }
Punti chiave sul codice
swipeToDismissBoxStategestisce lo stato del componente. Attiva il callbackconfirmValueChangeuna volta completata l'interazione con l'elemento. Il corpo del callback gestisce le diverse azioni possibili. Il callback restituisce un valore booleano che indica al componente se deve visualizzare un'animazione di chiusura. In questo caso:- Se l'elemento viene fatto scorrere dall'inizio alla fine, chiama la funzione lambda
onToggleDone, passando l'elementotodoItemcorrente. Questo corrisponde all'aggiornamento dell'attività da svolgere. - Se l'elemento viene fatto scorrere dalla fine all'inizio, chiama la funzione lambda
onRemove, passando l'elementotodoItemcorrente. Questo corrisponde all'eliminazione dell'attività. it != StartToEnd: questa riga restituiscetruese la direzione di scorrimento non èStartToEnd, altrimenti restituiscefalse. La restituzione difalseimpedisce la scomparsa immediata diSwipeToDismissBoxdopo uno scorrimento "Attiva/disattiva completato", consentendo una conferma visiva o un'animazione.
- Se l'elemento viene fatto scorrere dall'inizio alla fine, chiama la funzione lambda
SwipeToDismissBoxconsente interazioni di scorrimento orizzontale su ogni elemento. In stato di riposo, mostra i contenuti interni del componente, ma quando un utente inizia a scorrere, i contenuti vengono spostati e viene visualizzatobackgroundContent. Sia i contenuti normali sia ilbackgroundContentricevono i vincoli completi del contenitore principale in cui eseguire il rendering.contentviene disegnato soprabackgroundContent. In questo caso:backgroundContentè implementato comeIconcon un colore di sfondo basato suSwipeToDismissBoxValue:Bluequando scorriStartToEnd: attiva/disattiva un'attività da svolgere.Redquando scorriEndToStart: eliminazione di un'attività.- Non viene visualizzato nulla sullo sfondo per
Settled: quando l'elemento non viene fatto scorrere, non viene visualizzato nulla sullo sfondo. - Analogamente, l'elemento
Iconvisualizzato si adatta alla direzione di scorrimento: StartToEndmostra un'iconaCheckBoxquando l'attività è completata e un'iconaCheckBoxOutlineBlankquando non lo è.EndToStartmostra un'iconaDelete.
@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() ) } } }
Punti chiave sul codice
mutableStateListOf(...)crea un elenco osservabile che può contenere oggettiTodoItem. Quando un elemento viene aggiunto o rimosso da questo elenco, Compose ricompone le parti della UI che dipendono da questo elemento.- All'interno di
mutableStateListOf(), vengono inizializzati quattro oggettiTodoItemcon le rispettive descrizioni: "Paga le bollette", "Fai la spesa", "Vai in palestra" e "Cena".
- All'interno di
LazyColumnmostra un elenco a scorrimento verticale ditodoItems.onToggleDone = { todoItem -> ... }è una funzione di callback richiamata daTodoListItemquando l'utente contrassegna un oggetto come completato. Aggiorna la proprietàisItemDoneditodoItem. PoichétodoItemsè unmutableStateListOf, questa modifica attiva una ricomposizione, aggiornando la UI.onRemove = { todoItem -> ... }è una funzione di callback attivata quando l'utente rimuove l'elemento. Rimuove l'elementotodoItemspecifico dall'elencotodoItems. Inoltre, viene attivata una ricomposizione e l'elemento viene rimosso dall'elenco visualizzato.- A ogni
TodoListItemviene applicato un modificatoreanimateItemin modo che venga chiamato ilplacementSpecdel modificatore quando l'elemento viene ignorato. In questo modo, viene animata la rimozione dell'elemento e il riordinamento degli altri elementi nell'elenco.
Risultato
Il seguente video mostra la funzionalità di base di scorrimento per chiudere degli snippet precedenti:
Per il codice campione completo, consulta il file di codice sorgente GitHub.
Esempio avanzato: animazione del colore di sfondo allo scorrimento
Gli snippet seguenti mostrano come incorporare una soglia di posizione per animare il colore di sfondo di un elemento quando viene fatto scorrere.
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.") } ) } } }
Punti chiave sul codice
drawBehinddisegna direttamente sul canvas dietro i contenuti del componibileIcon.drawRect()disegna un rettangolo sul canvas e riempie l'intero perimetro dell'ambito di disegno con il coloreColorspecificato.
- Durante lo scorrimento, il colore di sfondo dell'elemento cambia gradualmente utilizzando
lerp.- Per uno scorrimento da
StartToEnd, il colore dello sfondo cambia gradualmente da grigio chiaro a blu. - Per uno scorrimento da
EndToStart, il colore dello sfondo cambia gradualmente da grigio chiaro a rosso. - La quantità di transizione da un colore all'altro è determinata da
swipeToDismissBoxState.progress.
- Per uno scorrimento da
OutlinedCardaggiunge una sottile separazione visiva tra gli elementi dell'elenco.
@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() ) } } }
Punti chiave sul codice
- Per i punti chiave di questo codice, consulta la sezione Punti chiave di una sezione precedente, che descrive uno snippet di codice identico.
Risultato
Il seguente video mostra la funzionalità avanzata con il colore di sfondo animato:
Per il codice campione completo, consulta il file di codice sorgente GitHub.