You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

未占满高度时LazyColumn+animateItem高度动画异常问题

问题描述

需要实现LazyColumn高度与内容完全匹配,同时通过.animateItem()实现项的进入/退出动画。当前使用.fillMaxHeight()时项动画正常,但不符合高度匹配需求;移除该修饰符后,LazyColumn的高度变更动画卡顿,且动画过程中最后一项会被截断、部分内容不可见。

复现代码:

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.singleWindowApplication
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

fun main() = singleWindowApplication {
    data class Item(val text: String, val id: Int)

    var list by remember { mutableStateOf(listOf(Item("a", 1), Item("b", 2), Item("c", 3))) }
    Box(modifier = Modifier.fillMaxSize()) {
        Row(
            modifier = Modifier
                .background(Color.DarkGray)
                .fillMaxSize()
                .clickable {
                    println("clicked")
                }
        ) {
        }
        Row(
            horizontalArrangement = Arrangement.End, modifier = Modifier
                .fillMaxWidth()
        ) {
            LazyColumn(
                modifier = Modifier
                    .background(Color.LightGray)
                    .fillMaxHeight()
                    .width(300.dp)
            ) {
                items(list, { it.id }) {
                    Column(modifier = Modifier.animateItem()) {
                        Text(it.text,
                            color = Color.White,
                            modifier = Modifier
                                .padding(10.dp)
                                .fillMaxWidth()
                                .background(Color.Red)
                                .padding(10.dp)
                                .clickable {
                                    println("clicked text")
                                })
                    }
                }
            }
        }
    }
    LaunchedEffect(Unit) {
        launch {
            while (true) {
                delay(1000)
                list = list.toMutableList().drop(1)
                if (list.isEmpty()) {
                    delay(1000)
                    list = listOf(Item("a", 1), Item("b", 2), Item("c", 3))
                }
            }
        }
    }
}
解决方案

核心问题是LazyColumn在无明确高度约束时,高度变更的动画过程中布局计算异常。通过以下调整解决:

  1. 移除.fillMaxHeight(),替换为.wrapContentHeight()让LazyColumn高度匹配内容
  2. 添加.animateContentSize()为LazyColumn的高度变化添加平滑动画,配合.animateItem()实现项动画与容器高度动画的协同

修改后的关键代码片段:

LazyColumn(
    modifier = Modifier
        .background(Color.LightGray)
        .wrapContentHeight() // 让高度匹配内容
        .animateContentSize() // 为容器高度变化添加动画
        .width(300.dp)
) {
    items(list, { it.id }) {
        Column(modifier = Modifier.animateItem()) {
            // 原Item内容保持不变
        }
    }
}

完整修改后的代码:

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.singleWindowApplication
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

fun main() = singleWindowApplication {
    data class Item(val text: String, val id: Int)

    var list by remember { mutableStateOf(listOf(Item("a", 1), Item("b", 2), Item("c", 3))) }
    Box(modifier = Modifier.fillMaxSize()) {
        Row(
            modifier = Modifier
                .background(Color.DarkGray)
                .fillMaxSize()
                .clickable {
                    println("clicked")
                }
        ) {
        }
        Row(
            horizontalArrangement = Arrangement.End, modifier = Modifier
                .fillMaxWidth()
        ) {
            LazyColumn(
                modifier = Modifier
                    .background(Color.LightGray)
                    .wrapContentHeight()
                    .animateContentSize()
                    .width(300.dp)
            ) {
                items(list, { it.id }) {
                    Column(modifier = Modifier.animateItem()) {
                        Text(it.text,
                            color = Color.White,
                            modifier = Modifier
                                .padding(10.dp)
                                .fillMaxWidth()
                                .background(Color.Red)
                                .padding(10.dp)
                                .clickable {
                                    println("clicked text")
                                })
                    }
                }
            }
        }
    }
    LaunchedEffect(Unit) {
        launch {
            while (true) {
                delay(1000)
                list = list.toMutableList().drop(1)
                if (list.isEmpty()) {
                    delay(1000)
                    list = listOf(Item("a", 1), Item("b", 2), Item("c", 3))
                }
            }
        }
    }
}

原理说明

  • .wrapContentHeight():让LazyColumn的高度自适应内容总高度,满足高度匹配需求
  • .animateContentSize():监听LazyColumn的尺寸变化,自动生成平滑的尺寸过渡动画,避免高度突变导致的布局异常
  • .animateItem():保持项的进入/退出动画,两者配合后容器高度动画与项动画同步,解决了截断和卡顿问题

内容的提问来源于stack exchange,提问作者Dima

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 09:04:59