AnimatedVisibility的退出和进入动画显示不正确

问题描述 投票:0回答:1

我尝试使用 AnimatedVisibility 和 Modifier.pointerInput 函数来实现用户可以将其滑出以删除列表中的项目的效果。我发现 exit 和 Enter animate 显示不正确,这让我很困惑。项目出现和消失没有任何动画。我不知道出了什么问题。我想知道为什么会这样,或者是否有任何方法可以帮助我确定为什么预期的动画不起作用。预先感谢。

@Composable
fun SwipedContent (
    swipeThreshold: Float = 500f,
    isVisibility: () -> Boolean,
    modifier: Modifier = Modifier,
    onSwipe: () -> Unit,
    content: @Composable () -> Unit
) {
    val offsetX = remember { Animatable(0f) }

    val scope = rememberCoroutineScope()

    AnimatedVisibility (
        visible = isVisibility.invoke(),
        enter = fadeIn(tween(300)) + slideInHorizontally(
            initialOffsetX = { it }
        ),
        exit = fadeOut(tween(300)) + slideOutHorizontally(
            targetOffsetX = { fullWidth ->
                if (fullWidth > 0) {
                    fullWidth
                } else {
                    -fullWidth
                }
            }
        )
    ) {
        Box (
            modifier = modifier
                .pointerInput(Unit) {
                    detectHorizontalDragGestures(
                        onDragEnd = {
                            if (offsetX.value > swipeThreshold || offsetX.value < -swipeThreshold) {
                                onSwipe.invoke()
                            } else {
                                scope.launch { offsetX.animateTo(0f) }
                            }
                        }
                    ) { change, dragAmount ->
                        change.consume()
                        scope.launch { offsetX.snapTo(offsetX.value + dragAmount) }
                    }
                }
                .offset { IntOffset(offsetX.value.roundToInt(), 0) },
        ) {
            content.invoke()
        }
    }
}
initialAlertList.forEachIndexed { index, alert ->
            key (alert.id) {
                SwipedContent (
                    isVisibility = { initialAlertList.contains(alert) },
                    onSwipe = { initialAlertList.remove(alert) }
                ) {
                    Card (
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(vertical = 8.dp, horizontal = 5.dp)
                            .clickable(
                                onClick = {
                                    editAlertIndexState.intValue = index
                                    isShowPopUp.value = !isShowPopUp.value
                                },
                                indication = ripple(),
                                interactionSource = remember { MutableInteractionSource() }
                            ),
                        shape = RoundedCornerShape(8.dp),
                        colors = CardDefaults.cardColors().copy(containerColor = Color.Transparent),
                        border = BorderStroke(width = 1.dp, color = Color.Gray),
                    ) {
                        // someComponents here
                    }
                }
            }
        }
android kotlin android-jetpack-compose
1个回答
0
投票

onSwipe
回调中,您从列表中删除该项目。这会触发重新组合,并再次执行
initialAlertList.forEachIndexed
循环,但相关项目不再存在,因此该项目的
SwipedContent
被跳过,以及其中的 AnimatedVisibility,因此无法显示不再退出动画了。

您需要在滑动时将项目保留在列表中,并将其标记为已删除。一种方法是将新属性添加到

Alert
数据类:

val visible: Boolean = true,

然后你可以像这样调用 SwipedContent :

SwipedContent(
    isVisibility = { alert.visible },
    onSwipe = { initialAlertList[index] = alert.copy(visible = false) },
)

当用户滑动时,该项目被标记为

visible = false
但仍保留在列表中。重组时,仍会为该“已删除”项目调用 SwipedContent(它并未真正删除,只是标记为不可见),并且其 AnimatedVisibility 将识别可见性的变化并触发退出动画。

如果您想等待动画结束,然后真正从列表中删除该项目,请参阅此处:https://stackoverflow.com/a/68640459


我猜您已将

initialAlertList.forEachIndexed
循环与
key
放在列中。这似乎有点尴尬;你为什么不直接使用一个内置的简单的 LazyColumn 呢?

LazyColumn {
    itemsIndexed(
        items = initialAlertList,
        key = { _, item -> item.id },
    ) { index, alert ->
        SwipedContent(/*...*/)
    }
}

当项目不适合时,这还可以启用列滚动,您甚至可以将

Modifier.animateItem()
传递给 SwipedContent。这将允许 LazyColumn 使项目跟随被删除的项目轻轻地向上滑动以填充其空间,而不是立即跳起来。仅当该项目实际上从列表中“删除”时才有效,而不仅仅是设置为不可见。请参阅上一节的最后一段。

最后,通过您的 SwipedContent,您似乎重新发明了内置的
SwipeToDismissBox

。为此,您需要一个 rememberSwipeToDismissBoxState() ,您可以在其中设置

500f
阈值,但它也不提供自动触发的退出动画,因此您必须在调用状态的
confirmValueChange
时创建自己的动画与所需的值。
仅供参考。

© www.soinside.com 2019 - 2024. All rights reserved.