【问题标题】:AnimatedVisibility & SwipeToDismiss Enter Animation does not trigger - Jetpack ComposeAnimatedVisibility 和 SwipeToDismiss Enter 动画不会触发 - Jetpack Compose
【发布时间】:2021-08-25 17:55:28
【问题描述】:

好的,所以我一直在尝试在我的应用中实现 滑动删除 功能。每当我从列表中滑动其中一个项目时,我都能看到后面的 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
                        )
                    }
                )
            }
        }
    }

}

【问题讨论】:

    标签: android kotlin android-jetpack-compose


    【解决方案1】:

    首先,您不应该在可组合内执行任何状态更改操作。而是使用其中一个副作用,通常是LaunchedEffect(key) { }:块的内容将在第一次渲染时调用,并且每次键都与上次渲染不同。此外,您已经在协程范围内,因此无需启动它。在documentation 中查看有关副作用的更多信息。

    列表中的项目动画是not yet supported。就像在项目中添加AnimatedVisibility 一样简单。

    当compose第一次在compose树中看到AnimatedVisibility时,它会在没有动画的情况下绘制(或不绘制)它。

    当下次重构时visible 与上次渲染时间不同时,它会生成动画。

    因此,要使其按您的意愿工作,您可以执行以下操作:

    1. 添加itemAppeared状态值,这将使列表中的项目最初隐藏,并使用副作用使其在渲染后立即可见
    2. 添加 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)
                        }
                    )
                }
            }
        }
    }
    

    【讨论】:

    • 谢谢菲利普!它可以工作,但进行了一项修改,而不是将 Unit 传递给 LaunchedEffect,我需要将 true 作为 key1 参数传递。
    • @Hassa 如果你传递静态值true 它应该与Unit 完全一样工作
    • 我尝试过使用 Unit,但这行代码没有触发:onSwipeToDelete(Action.DELETE, task)
    • @TarasMykhalchuk 不客气。由于此答案某些系统动画 API 可用,您可以查看维护者制作的 this repo 中的示例。
    猜你喜欢
    • 2023-03-21
    • 2022-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    • 1970-01-01
    相关资源
    最近更新 更多