如何在 Jetpack Compose Android 上的 LazyColumn 中显示项目视图的动画

Aja*_*pal 7 android android-jetpack-compose

我在惰性列视图中有一个项目列表。

当我们从列表中删除一项时,我们如何显示动画。

我需要为被删除的视图设置动画。删除操作是通过按下视图内的删除图标来完成的。 在此处输入图片说明

我尝试了 AnimationVisibility 并且它没有按预期工作。

在此处输入图片说明

Zak*_*ikh 38

添加了对惰性列表项目位置进行动画处理的实验能力。

LazyItemScope名为 的中有一个新的可用修饰符Modifier.animateItemPlacement()。如果您为每个项目提供唯一的值,则此方法有效key

使用示例:

var list by remember { mutableStateOf(listOf("A", "B", "C")) }
LazyColumn {
    item {
        Button(onClick = { list = list.shuffled() }) {
            Text("Shuffle")
        }
    }
    items(list, key = { it }) {
        Text("Item $it", Modifier.animateItemPlacement())
    }
}
Run Code Online (Sandbox Code Playgroud)

LazyListScope.item当您通过或提供键时,LazyListScope.items此修饰符将启用项目重新排序动画。除了项目重新排序之外,由排列或对齐更改等事件引起的所有其他位置更改也将被动画化。

  • 我向他们提供了钥匙,但没有任何变化。当我打开屏幕时,它们只是出现,没有任何动画 (7认同)

Yas*_*ass 8

它尚未得到官方支持,但他们正在努力。你可能可以实现它,但以一种hacky的方式。

当您的列表更新时,您的可组合项会重新创建,并且它尚不支持项目的动画,因此您必须在项目上添加一个布尔变量并在“删除”时更改该值,而不是将其从列表中删除。显示更新后的列表后,您可以为要删除的项目设置动画并延迟,然后在动画结束后更新列表。

我没有亲自测试过这种方法,所以它可能无法按预期工作,但这是我能想到的不支持更新动画的惰性列表的唯一方法。


axe*_*ans 5

就像YASAN所说的那样,我可以使用AnimatedVisibility在 LazyColumn 项目上生成“slideOut”+“fadeOut”动画,只需isVisible在项目的 DataClass 上添加属性并将项目视图包装在AnimatedVisibilityComposable 中即可。由于该 api 仍处于实验阶段,请小心。

如果您或其他人可能会寻找它,我将把我的片段放在这里供您参考。

为了LazyColumn

LazyColumn {
    items(
        items = notes,
        key = { item: Note -> item.id }
    ) { item ->
        AnimatedVisibility(
            visible = item.isVisible,
            exit = fadeOut(
                animationSpec = TweenSpec(200, 200, FastOutLinearInEasing)
            )
        ) {
            ItemNote(
                item
            ) {
                notes = changeNoteVisibility(notes, it)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于可组合项

@ExperimentalAnimationApi
@ExperimentalMaterialApi
@Composable
fun ItemNote(
    note: Note,
    onSwipeNote: (Note) -> Unit
) {
    val iconSize = (-68).dp
    val swipeableState = rememberSwipeableState(0)
    val iconPx = with(LocalDensity.current) { iconSize.toPx() }
    val anchors = mapOf(0f to 0, iconPx to 1)

    val coroutineScope = rememberCoroutineScope()

    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(75.dp)
            .swipeable(
                state = swipeableState,
                anchors = anchors,
                thresholds = { _, _ -> FractionalThreshold(0.5f) },
                orientation = Orientation.Horizontal
            )
            .background(Color(0xFFDA5D5D))
    ) {
        Box(
            modifier = Modifier
                .fillMaxHeight()
                .align(Alignment.CenterEnd)
                .padding(end = 10.dp)
        ) {
            IconButton(
                modifier = Modifier.align(Alignment.Center),
                onClick = {
                    Log.d("Note", "Deleted")
                    coroutineScope.launch {
                        onSwipeNote(note)
                    }
                }
            ) {
                Icon(
                    Icons.Default.Delete,
                    contentDescription = "Delete this note",
                    tint = Color.White
                )
            }
        }

        AnimatedVisibility(
            visible = note.isVisible,
            exit = slideOutHorizontally(
                targetOffsetX = { -it },
                animationSpec = TweenSpec(200, 0, FastOutLinearInEasing)
            )
        ) {
            ConstraintLayout(
                modifier = Modifier
                    .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
                    .fillMaxHeight()
                    .fillMaxWidth()
                    .background(Color.White)
            ) {
                val (titleText, contentText, divider) = createRefs()

                Text(
                    modifier = Modifier.constrainAs(titleText) {
                        top.linkTo(parent.top, margin = 12.dp)
                        start.linkTo(parent.start, margin = 18.dp)
                        end.linkTo(parent.end, margin = 18.dp)
                        width = Dimension.fillToConstraints
                    },
                    text = note.title,
                    fontSize = 16.sp,
                    fontWeight = FontWeight(500),
                    textAlign = TextAlign.Start
                )

                Text(
                    modifier = Modifier.constrainAs(contentText) {
                        bottom.linkTo(parent.bottom, margin = 12.dp)
                        start.linkTo(parent.start, margin = 18.dp)
                        end.linkTo(parent.end, margin = 18.dp)
                        width = Dimension.fillToConstraints
                    },
                    text = note.content,
                    textAlign = TextAlign.Start
                )

                Divider(
                    modifier = Modifier.constrainAs(divider) {
                        start.linkTo(parent.start)
                        end.linkTo(parent.end)
                        bottom.linkTo(parent.bottom)
                        width = Dimension.fillToConstraints
                    },
                    thickness = 1.dp,
                    color = Color.DarkGray
                )
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

还有数据类Note

data class Note(
    var id: Int,
    var title: String = "",
    var content: String = "",
    var isVisible: Boolean = true
)
Run Code Online (Sandbox Code Playgroud)