Il componente SwipeToDismissBox
consente a un utente di ignorare o aggiornare un elemento scorrendo verso sinistra o verso destra.
API surface
Utilizza il composable SwipeToDismissBox
per implementare le azioni attivate
da gesti di scorrimento. I parametri principali includono:
state
: lo statoSwipeToDismissBoxState
creato per memorizzare il valore prodotto dai calcoli sull'elemento scorrimento, che attiva gli eventi quando viene prodotto.backgroundContent
: un componibile personalizzabile visualizzato dietro i contenuti dell'articolo che viene rivelato quando si scorre.
Esempio di base: aggiornamento o chiusura con scorrimento
Gli snippet in questo esempio mostrano un'implementazione dello scorrimento che aggiorna l'elemento quando viene eseguito dall'inizio alla fine o lo chiude quando viene eseguito 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 del codice
swipeToDismissBoxState
gestisce lo stato del componente. Attiva il callbackconfirmValueChange
al termine dell'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 mostrare un'animazione di chiusura. In questo caso:- Se l'elemento viene strisciato dall'inizio alla fine, viene chiamata la funzione lambda
onToggleDone
, passando l'attualetodoItem
. Questo corrisponde all'aggiornamento dell'elemento della lista di cose da fare. - Se l'elemento viene strisciato dall'inizio alla fine, viene chiamata la funzione lambda
onRemove
, passando l'attualetodoItem
. Ciò corrisponde all'eliminazione dell'elemento della lista di cose da fare. it != StartToEnd
: questa riga restituiscetrue
se la direzione dello scorrimento non èStartToEnd
efalse
in caso contrario. Il ritorno afalse
impedisce cheSwipeToDismissBox
scompaia immediatamente dopo uno scorrimento "Attiva/Disattiva completato", consentendo una conferma visiva o un'animazione.
- Se l'elemento viene strisciato dall'inizio alla fine, viene chiamata la funzione lambda
SwipeToDismissBox
consente le interazioni con 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 siabackgroundContent
ricevono i vincoli completi del contenitore principale per il rendering. Ilcontent
viene disegnato sopra ilbackgroundContent
. In questo caso:backgroundContent
è implementato comeIcon
con un colore di sfondo basato suSwipeToDismissBoxValue
:Blue
quando scorriStartToEnd
: attiva/disattiva un elemento della lista di cose da fare.Red
quando scorriEndToStart
: eliminazione di un elemento della lista di cose da fare.- Non viene visualizzato nulla in background per
Settled
: quando l'elemento non viene scorretto, non viene visualizzato nulla in background. - Allo stesso modo, il
Icon
visualizzato si adatta alla direzione dello scorrimento: StartToEnd
mostra un'iconaCheckBox
quando l'elemento della lista di cose da fare è stato completato e un'iconaCheckBoxOutlineBlank
quando non è stato completato.EndToStart
viene visualizzata 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 del codice
mutableStateListOf(...)
crea un elenco osservabile che può contenere oggettiTodoItem
. Quando un elemento viene aggiunto o rimosso da questo elenco, Compose ricomponie le parti dell'interfaccia utente che dipendono da esso.- All'interno di
mutableStateListOf()
, vengono inizializzati quattro oggettiTodoItem
con le rispettive descrizioni: "Paga le bollette", "Fai la spesa", "Vai in palestra" e "Prendi la cena".
- All'interno di
LazyColumn
mostra un elenco ditodoItems
in scorrimento verticale.onToggleDone = { todoItem -> ... }
è una funzione di callback invocata daTodoListItem
quando l'utente contrassegna un oggetto come completato. Aggiorna la proprietàisItemDone
ditodoItem
. PoichétodoItems
è unmutableStateListOf
, questa modifica attiva una ricompozione, aggiornando l'interfaccia utente.onRemove = { todoItem -> ... }
è una funzione di callback attivata quando l'utente rimuove l'elemento. Rimuove iltodoItem
specifico dall'elencotodoItems
. Ciò comporta anche una ricostituzione e l'elemento verrà rimosso dall'elenco visualizzato.- A ogni
TodoListItem
viene applicato un modificatoreanimateItem
in modo che ilplacementSpec
del modificatore venga chiamato quando l'elemento viene ignorato. In questo modo viene animata la rimozione dell'elemento, nonché il riordinamento degli altri elementi nell'elenco.
Risultato
Il video seguente mostra la funzionalità di scorrimento per chiudere di base degli snippet precedenti:
Per il codice di esempio completo, consulta il file di origine di GitHub.
Esempio avanzato: animare il colore di sfondo con lo scorrimento
Gli snippet riportati di seguito mostrano come incorporare una soglia di posizione per animare il colore di sfondo di un elemento quando viene scorretto.
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 del codice
drawBehind
viene disegnato direttamente nella tela dietro i contenuti del composableIcon
.drawRect()
disegna un rettangolo sul canvas e riempie l'intero ambito del disegno con il coloreColor
specificato.
- Quando scorri, il colore di sfondo dell'elemento passa gradualmente da un colore all'altro utilizzando
lerp
.- Se scorri da
StartToEnd
, il colore di sfondo cambia gradualmente da grigio chiaro a blu. - Se scorri da
EndToStart
, il colore di sfondo cambia gradualmente da grigio chiaro a rosso. - L'entità della transizione da un colore all'altro è determinata da
swipeToDismissBoxState.progress
.
- Se scorri da
OutlinedCard
aggiunge una sottile separazione visiva tra le voci 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 del codice
- Per i punti chiave di questo codice, consulta Punti chiave di una sezione precedente, che descrive uno snippet di codice identico.
Risultato
Il video seguente mostra la funzionalità avanzata con colore di sfondo animato:
Per il codice di esempio completo, consulta il file di origine di GitHub.