我将
stickyHeader
与 LazyColumn
一起使用,我想在单击标题时展开和折叠每个标题下的项目,并具有流畅的动画。我已经使用 AnimatedVisibility
实现了此行为,这对于少量项目来说效果很好。
但是,当标题下的项目数量变大(例如,超过 100 个项目)时,UI 在动画过程中开始显着滞后。
是否有更好的方法来实现这种具有更好性能的扩展和折叠行为,或者我可以对
AnimatedVisibility
进行任何优化吗?
任何建议或替代方法表示赞赏!
当前实施:
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun AnimatedImageWithTextItem() {
val state = remember { mutableStateMapOf<String, Boolean>() }
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
) {
val groupedItems = list.groupBy { it.date }
groupedItems.onEachIndexed { groupIndex, (key, elements) ->
val isExpanded = state[key] ?: true
stickyHeader {
Row(modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.background(Color.Yellow)
.clickable { state[key] = !isExpanded })
{
Text("header $key")
}
}
itemsIndexed(elements) { elementIndex, element ->
ExpandableContent(isExpanded) {
Row(modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.background(Color.White)
.clickable { state[key] = !isExpanded })
{
Text("Item of the header")
}
}
}
}
}
}
const val EXPANSTION_TRANSITION_DURATION = 300
@Composable
fun ExpandableContent(
visible: Boolean = true,
content: @Composable () -> Unit
) {
val enterTransition = remember {
expandVertically(
expandFrom = Alignment.Top,
animationSpec = tween(EXPANSTION_TRANSITION_DURATION)
) + fadeIn(
initialAlpha = 0.3f,
animationSpec = tween(EXPANSTION_TRANSITION_DURATION)
)
}
val exitTransition = remember {
shrinkVertically(
// Expand from the top.
shrinkTowards = Alignment.Top,
animationSpec = tween(EXPANSTION_TRANSITION_DURATION)
) + fadeOut(
// Fade in with the initial alpha of 0.3f.
animationSpec = tween(EXPANSTION_TRANSITION_DURATION)
)
}
AnimatedVisibility(
visible = visible,
enter = enterTransition,
exit = exitTransition
) {
content()
}
}
您在每次重组时都调用
val groupedItems = list.groupBy { it.date }
。这可能就是问题所在。
https://developer.android.com/develop/ui/compose/performance/bestpractices#use-remember
可组合函数可以非常频繁地运行,就像每个 动画的帧。因此,您应该尽可能少做 尽可能在可组合项的主体中进行计算。
一项重要的技术是将计算结果存储为 记住。这样,计算运行一次,您就可以获取 随时需要结果。
例如,下面是一些显示排序后的姓名列表的代码, 但排序的方式非常昂贵:
@Composable
fun ContactList(
contacts: List<Contact>,
comparator: Comparator<Contact>,
modifier: Modifier = Modifier
) {
LazyColumn(modifier) {
// DON’T DO THIS
items(contacts.sortedWith(comparator)) { contact ->
// ...
}
}
}