Reputation: 4231
Okay so I've been trying to implement swipe to delete function in my app. Whenever I swipe one of the items from the list I'm able to see a RedBackground behind and everything works fine. Also the swipe animation when I delete an item is triggered successfully. (Even though I'm not sure if it's a good idea to use delay for that? I can't think of any other way to do it). But the enter animation when I add an item to the database/list is not working, and I'm not sure why. Here's the code of my Lazy Column
@Composable
fun DisplayTasks(
tasks: List<ToDoTask>,
onSwipeToDelete: (Action, ToDoTask) -> Unit,
navigateToTaskScreen: (Int) -> Unit
) {
LazyColumn {
items(
items = tasks,
key = { task ->
task.id
}
) { task ->
val dismissState = rememberDismissState()
val dismissDirection = dismissState.dismissDirection
val isDismissed = dismissState.isDismissed(DismissDirection.EndToStart)
if (isDismissed && dismissDirection == DismissDirection.EndToStart
) {
val scope = rememberCoroutineScope()
scope.launch {
delay(300)
onSwipeToDelete(Action.DELETE, task)
}
}
AnimatedVisibility(
visible = !isDismissed,
exit = shrinkVertically(
animationSpec = tween(
durationMillis = 300,
)
),
enter = expandVertically(
animationSpec = tween(
durationMillis = 300
)
)
) {
SwipeToDismiss(
state = dismissState,
directions = setOf(DismissDirection.EndToStart),
dismissThresholds = { FractionalThreshold(0.2f) },
background = { RedBackground() },
dismissContent = {
LazyColumnItem(
toDoTask = task,
navigateToTaskScreen = navigateToTaskScreen
)
}
)
}
}
}
}
Upvotes: 3
Views: 3250
Reputation: 87794
First of all, you shouldn't perform any state changing actions inside composable. Instead use one of side effects, usually LaunchedEffect(key) { }
: content of the block will be called on the first render and each time key is different from the last render. Also inside you're already in a coroutine scope, so no need to launch it. Check out more about side-effects in the documentation.
Item animation in the list is not yet supported. It's as simple as adding AnimatedVisibility
to the items.
When compose firstly sees AnimatedVisibility
in the compose tree, it draws(or not draws) it without animation.
And when on next recomposition visible
is different from the last render time, it animates.
So to make it work as you wish you can do the following:
itemAppeared
state value, which will make item in the list initially hidden, and using side effect make it visible right after rendercolumnAppeared
which will prevent initial appearance animation - without it when screen renders all items will appear animatedly too@Composable
fun DisplayTasks(
tasks: List<ToDoTask>,
onSwipeToDelete: (Action, ToDoTask) -> Unit,
) {
var columnAppeared by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
columnAppeared = true
}
LazyColumn {
items(
items = tasks,
key = { task ->
task.id
}
) { task ->
val dismissState = rememberDismissState()
val dismissDirection = dismissState.dismissDirection
val isDismissed = dismissState.isDismissed(DismissDirection.EndToStart)
if (isDismissed && dismissDirection == DismissDirection.EndToStart
) {
LaunchedEffect(Unit) {
delay(300)
onSwipeToDelete(Action.DELETE, task)
}
}
var itemAppeared by remember { mutableStateOf(!columnAppeared) }
LaunchedEffect(Unit) {
itemAppeared = true
}
AnimatedVisibility(
visible = itemAppeared && !isDismissed,
exit = shrinkVertically(
animationSpec = tween(
durationMillis = 300,
)
),
enter = expandVertically(
animationSpec = tween(
durationMillis = 300
)
)
) {
SwipeToDismiss(
state = dismissState,
directions = setOf(DismissDirection.EndToStart),
dismissThresholds = { FractionalThreshold(0.2f) },
background = {
Box(
Modifier
.background(Color.Red)
.fillMaxSize()
)
},
dismissContent = {
Text(task.id)
}
)
}
}
}
}
Upvotes: 4