我有一个懒加载列视图的项目列表。
我们如何在从列表中删除一个项目时显示动画。
我需要为即将被删除的视图添加动画效果。删除操作是通过在视图内部按下删除图标完成的。
我尝试使用AnimationVisibility
,但它并没有按照预期工作。
我有一个懒加载列视图的项目列表。
我们如何在从列表中删除一个项目时显示动画。
我需要为即将被删除的视图添加动画效果。删除操作是通过在视图内部按下删除图标完成的。
我尝试使用AnimationVisibility
,但它并没有按照预期工作。
新增了对惰性列表项位置进行动画处理的实验性功能。
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())
}
}
当您通过LazyListScope.item
或LazyListScope.items
提供键时,此修饰符将启用项目重新排序动画。除了项目重新排序外,由排列或对齐更改等事件引起的所有其他位置更改也将被动画化。
Compose 1.1.0 更新:
现在可以通过 Modifier.animateItemPlacement()
来实现动画元素位置的更改,但删除/插入动画仍然不可行,需要使用我所解释的方法手动实现。
要实现项目位置更改的动画效果,只需在列表中提供项目键值对,例如 key={ it.id }
。
原回答:
目前官方还没有正式支持这一功能,但正在研究中。您可能可以使用一种“hacky”方法来实现。
当列表更新时,您的Composable将被重新创建,但它尚不支持用于项目的动画,因此您必须在项目上添加一个布尔变量,并在其被“删除”时更改该值,而不是从列表中删除。显示更新后的列表后,您可以延迟动画删除该项目,然后在动画结束后将其从列表中删除。
我个人没有测试过此方法,因此它可能无法按预期工作,但这是我能想到的唯一的方法,因为lazy lists不支持更新动画。
像 YASAN 所说的那样,通过在你的项目数据类中添加 isVisible
属性,然后将你的项目视图包装在 AnimatedVisibility
组合中,你可以使用 AnimatedVisibility 来在 LazyColumn
项上制作 'slideOut' + 'fadeOut' 动画。由于该 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)
}
}
}
}
对于 Item Composable
@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
)
}
}
}
}
此外,数据类Note
data class Note(
var id: Int,
var title: String = "",
var content: String = "",
var isVisible: Boolean = true
)
我只是试验一下,但或许这可以在他们建立出正式解决方案之前帮上忙。
@Composable
fun <T> T.AnimationBox(
enter: EnterTransition = expandVertically() + fadeIn(),
exit: ExitTransition = fadeOut() + shrinkVertically(),
content: @Composable T.() -> Unit
) {
val state = remember {
MutableTransitionState(false).apply {
// Start the animation immediately.
targetState = true
}
}
AnimatedVisibility(
visibleState = state,
enter = enter,
exit = exit
) { content() }
}
LazyColumn(
state = lazyState
) {
item {
AnimationBox {
Item(text = "TEST1!")
}
AnimationBox {
Item(text = "TEST2!")
}
}
}
我创建了一个Gist,解决了在LazyColumn中添加项的动画问题。非常容易添加删除项的动画效果。希望你会觉得有用。
https://gist.github.com/EudyContreras/f91b20c49552e02607816b3aea6e7f43
如果您实现了compose
Version 1.1.0-beta03,现在我们有一种新的方式可以对项目进行动画处理。
animateItemPlacement
放在SwipeToDismiss
组合中的一个修饰符中,就像这样:LazyColumn {
items(...) {
val dismissState = rememberDismissState()
SwipeToDismiss(
modifier = Modifier.animateItemPlacement(),
...
) {
...
}
}
}
@OptIn(ExperimentalFoundationApi::class)
。