android - AnimatedVisibility 和 SwipeToDismiss Enter 动画不会触发 - Jetpack Compose
问题描述
好的,所以我一直在尝试在我的应用程序中实现滑动删除功能。每当我从列表中滑动其中一个项目时,我都能看到后面的 RedBackground 并且一切正常。我删除项目时的滑动动画也被成功触发。(即使我不确定为此使用延迟是否是个好主意?我想不出任何其他方式来做到这一点)。但是当我将项目添加到数据库/列表时的输入动画不起作用,我不知道为什么。这是我的懒惰专栏的代码
@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
)
}
)
}
}
}
}
解决方案
首先,您不应该在可组合内执行任何状态更改操作。取而代之的是使用一种副作用,通常是LaunchedEffect(key) { }
:块的内容将在第一次渲染时调用,并且每次键都与最后一次渲染不同。此外,您已经在协程范围内,因此无需启动它。在文档中查看有关副作用的更多信息。
尚不支持列表中的项目动画。它就像添加AnimatedVisibility
到项目一样简单。
当 compose 第一次AnimatedVisibility
在 compose 树中看到时,它会在没有动画的情况下绘制(或不绘制)它。
并且当下一次重组visible
与上次渲染时间不同时,它会进行动画处理。
因此,要使其按您的意愿工作,您可以执行以下操作:
- 添加
itemAppeared
状态值,这将使列表中的项目最初隐藏,并使用副作用使其在渲染后立即可见 - 添加
columnAppeared
这将阻止初始外观动画 - 没有它,当屏幕呈现所有项目时,所有项目也会以动画方式出现
@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)
}
)
}
}
}
}
推荐阅读
- pine-script - 无法关闭策略
- python - /quizmaker/ 处的 IntegrityError(1048,“列 'id_id' 不能为空”)
- css - React 组件从上一页获取 css
- java - 在 Java 中快速比较大数据集中的值和小数据集中的值
- junit - 在单个自动化测试中评估多个测试用例的技术?
- python - 如何枚举 Spark 的 DataFrame 中的列?如果列是嵌套的怎么办?
- java - org.xml.sax.SAXParseException,Mule 4.3,Anypoint studio 7.8
- io - 高效读取输入文件
- jquery - 通过 jQuery + CSS 在右上角显示消息
- arguments - 从“剧本”子面板询问如何将“策略”与“帐户”联系起来