Saltearse al contenido

SwipeToDismiss

MaterialMaterial 3
Imagen del componente SwipeToDismiss MaterialImagen del componente SwipeToDismiss Material

El componente SwipeToDismiss permite a los usuarios realizar acciones en un elemento de la lista deslizando horizontalmente sobre él (generalmente hacia la izquierda o la derecha). Aunque comúnmente se utiliza para eliminar elementos, este componente también puede configurarse para llevar a cabo otras acciones como archivar, marcar como leído/no leído, agregar a favoritos, entre otros. Esta interacción mejora la experiencia del usuario al proporcionar una forma rápida y eficiente de manejar elementos en una lista.

Implementación

Definición del componente

Terminal window
@Composable
fun SwipeToDismiss(
state: DismissState,
background: @Composable RowScope.() -> Unit,
dismissContent: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
directions: Set<DismissDirection> = setOf(EndToStart, StartToEnd),
dismissThresholds: (DismissDirection) -> ThresholdConfig = {
FixedThreshold(DISMISS_THRESHOLD)
},
)
AtributoDescripción
stateEstado que controla el deslizamiento del elemento, indicando si ha sido descartado o no.
backgroundFunción lambda que define el contenido que se muestra detrás del elemento mientras se está deslizando.
dismissContentFunción lambda que define el contenido principal del elemento que se puede deslizar.
modifierModificador opcional para personalizar el estilo y el diseño del componente.
directionsConjunto de direcciones en las que se permite el deslizamiento del elemento (por defecto, de derecha a izquierda y de izquierda a derecha).
dismissThresholdsConfigura que tanto deber ser deslizado un elemento para realizar una acción.

Ejemplos

Imagen del componente SwipeToDismiss Material
Terminal window
@file:OptIn(ExperimentalMaterialApi::class)
package com.example.swipes
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.DismissDirection
import androidx.compose.material.DismissState
import androidx.compose.material.DismissValue
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.SwipeToDismiss
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.rememberDismissState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.example.swipes.ui.theme.SwipesTheme
import kotlinx.coroutines.delay
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
SwipesTheme {
Surface(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background),
color = MaterialTheme.colors.background
) {
val programmingLanguages = rememberSaveable(
saver = ListSaver
) {
mutableStateListOf(
"Kotlin",
"C++",
"C#",
"Java",
"JavaScript",
"Swift",
"Python"
)
}
Scaffold (
topBar = {
TopAppBar(
title = {
Text(text = "Programming Languages")
}
)
}
){padding ->
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(padding)
) {
items(items = programmingLanguages, key = { it }) { language ->
SwipeToDeleteContainer(
item = language,
onDelete = { programmingLanguages.remove(language) }) { item ->
Text(
text = item,
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colors.background)
.padding(16.dp),
color = MaterialTheme.colors.primary
)
}
}
}
}
}
}
}
}
}
@Composable
fun <T> SwipeToDeleteContainer(
item: T,
onDelete: (T) -> Unit,
animationDuration: Int = 500,
content: @Composable (T) -> Unit
) {
var isRemoved by remember { mutableStateOf(false) }
val dismissState = rememberDismissState(confirmStateChange = { value ->
if (value == DismissValue.DismissedToStart) {
isRemoved = true
true
} else {
false
}
})
LaunchedEffect(key1 = isRemoved) {
if (isRemoved) {
delay(animationDuration.toLong())
onDelete(item)
}
}
AnimatedVisibility(
visible = !isRemoved,
exit = shrinkVertically(
animationSpec = tween(durationMillis = animationDuration),
shrinkTowards = Alignment.Top
) + fadeOut()
) {
SwipeToDismiss(
state = dismissState,
background = {
DeleteBackground(swipeDismissState = dismissState)
},
dismissContent = { content(item) },
directions = setOf(DismissDirection.EndToStart)
)
}
}
@Composable
fun DeleteBackground(
swipeDismissState: DismissState
) {
val color = if (swipeDismissState.dismissDirection == DismissDirection.EndToStart) {
Color.Red
} else Color.Transparent
Box(
modifier = Modifier
.fillMaxSize()
.background(color)
.padding(16.dp),
contentAlignment = Alignment.CenterEnd
) {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = null,
tint = Color.White
)
}
}
val ListSaver: Saver<MutableList<String>, Any> = listSaver(
save = { stateList ->
stateList.toList()
},
restore = { list ->
mutableStateListOf<String>().apply { addAll(list) }
}
)