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

Jetpack Compose:如何在LazyColumn中实现展开显列表的可折叠卡片

解决Jetpack Compose LazyColumn中可折叠卡片的滚动联动问题

我在Jetpack Compose的LazyColumn中添加可折叠卡片时遇到了问题:当卡片展开显示章节列表时,上方的卡片无法像LazyColumn的正常项一样滚出屏幕。

问题根源

当前实现的核心问题是在ExpandableCard内部嵌套了LazyColumn,这导致章节列表的滚动被限制在卡片内部,父LazyColumn只会将整个ExpandableCard视为一个固定高度的项,无法联动滚动让上方卡片滚出视野。

解决方案

将所有内容(卡片头部+展开的章节)整合到同一个父LazyColumn中,利用LazyColumn的动态item特性实现折叠/展开,避免嵌套滚动组件。


修改步骤与代码

1. 定义主题状态类

用于管理每个主题的展开状态:

data class SubjectState(val subject: Subjects, var isExpanded: Boolean = false)

2. 初始化状态列表

在父Composable中创建并维护所有主题的状态:

val subjectsList = listOf(
    PhysicsMechanics,
    PhysicsThermodynamics,
    PhysicsSound,
    PhysicsOptics,
    PhysicsElectrostatics,
    PhysicsElectricityAndMagnetism,
    PhysicsModernPhysics
)
val subjectStates = remember { subjectsList.map { SubjectState(it) }.toMutableStateList() }

3. 重构父LazyColumn

将卡片头部和展开的章节统一作为父LazyColumn的item:

LazyColumn {
    subjectStates.forEachIndexed { index, state ->
        // 卡片头部项
        item(key = state.subject.name) {
            ExpandableCardHeader(
                subject = state.subject,
                isExpanded = state.isExpanded,
                onToggle = {
                    subjectStates[index] = state.copy(isExpanded = !state.isExpanded)
                }
            )
            Spacer(modifier = Modifier.height(2.dp))
        }
        // 展开时显示章节项
        if (state.isExpanded) {
            items(state.subject.chapters, key = { it.name }) { chapter ->
                ChapterBox(chapterName = chapter)
                Spacer(modifier = Modifier.height(10.dp))
            }
        }
    }
}

4. 拆分卡片头部组件

将原ExpandableCard拆分为仅负责头部交互的组件:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ExpandableCardHeader(
    subject: Subjects,
    isExpanded: Boolean,
    onToggle: () -> Unit,
    modifier: Modifier = Modifier
) {
    val rotationState by animateFloatAsState(
        targetValue = if (isExpanded) 180f else 0f, label = ""
    )

    Card(
        modifier = modifier
            .fillMaxWidth()
            .animateContentSize(
                animationSpec = tween(
                    durationMillis = 300,
                    easing = LinearOutSlowInEasing
                )
            ),
        shape = RoundedCornerShape(8.dp),
        onClick = onToggle
    ) {
        Row(
            horizontalArrangement = Arrangement.SpaceBetween,
            verticalAlignment = Alignment.CenterVertically,
            modifier = Modifier
                .padding(12.dp)
                .fillMaxWidth()
        ) {
            Text(
                text = subject.name,
                style = MaterialTheme.typography.titleMedium
            )

            IconButton(
                modifier = Modifier.rotate(rotationState),
                onClick = onToggle
            ) {
                Icon(
                    imageVector = Icons.Default.ArrowDropDown,
                    contentDescription = "展开/折叠章节"
                )
            }
        }
    }
}

5. 保留原有章节项组件

ChapterBox无需修改,直接复用:

@Composable
fun ChapterBox(
    modifier: Modifier = Modifier,
    chapterName: ChapterName
) {
    Box(
        modifier = modifier
            .fillMaxSize()
            .padding(2.dp)
            .background(color = Color(0xFF8F6F5FA), RoundedCornerShape(8.dp))
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(16.dp),
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp)
        ) {
            Image(painter = painterResource(id = chapterName.icon), contentDescription = null)
            Column {
                Text(text = chapterName.name, maxLines = 1, overflow = TextOverflow.Ellipsis)
                Spacer(Modifier.height(4.dp))
                Text(
                    text = chapterName.description,
                    style = MaterialTheme.typography.bodyMedium,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
            }
        }
    }
}

效果说明

修改后,所有内容都在同一个LazyColumn中,展开主题时,章节会作为动态item插入到列表中,整个列表的滚动是全局联动的,上方的卡片可以像普通LazyColumn项一样正常滚出屏幕。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 09:35:03