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

Jetpack Compose中DropdownMenu内Switch关闭菜单后状态不保存问题求助

问题原因

你代码里的categoryCheckedState每次Composable重组时都会被重新初始化所有值为true——因为categories.forEach { categoryCheckedState[category] = true }直接写在Composable根作用域,而非remember的初始化逻辑里。每次DropdownMenu关闭触发重组时,这行代码都会执行,把所有分类的选中状态重置为true,导致之前的选择丢失。

修正方案
  1. 正确初始化状态:把状态初始化逻辑放在remember的lambda中,确保只执行一次
  2. 移除冗余变量:删除未实际使用的selectedCategories
  3. 统一状态更新逻辑:合并DropdownMenuItem点击和Switch状态变化的处理逻辑,避免冲突

以下是修正后的完整代码:

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TaskPageLayout(
    contentPadding: PaddingValues = PaddingValues()
) {
    val categories = listOf(
        Category("Home"),
        Category("Work"),
        Category("Chores")
    )

    val tasks = listOf(
        Task("Task 1", categories[0], "High", "Easy"),
        Task("Task 2", categories[1], "Medium", "Medium"),
        Task("Task 3", categories[2], "Low", "Hard"),
        Task("Task 4", categories[0], "High", "Easy")
    )

    var expanded by remember { mutableStateOf(false) }

    // 仅在首次组合时初始化状态
    val categoryCheckedState = remember {
        mutableStateMapOf<Category, Boolean>().apply {
            categories.forEach { category ->
                this[category] = true
            }
        }
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(contentPadding)
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp),
            horizontalArrangement = Arrangement.SpaceAround
        ) {
            Box {
                ElevatedButton(onClick = { expanded = true }) {
                    Text("Category")
                }
                DropdownMenu(
                    expanded = expanded,
                    onDismissRequest = { expanded = false }
                ) {
                    categories.forEach { category ->
                        DropdownMenuItem(
                            text = { Text(category.name) },
                            trailingIcon = {
                                Switch(
                                    modifier = Modifier
                                        .semantics {
                                            contentDescription =
                                                "Switch to choose which categories to view"
                                        },
                                    checked = categoryCheckedState[category] ?: false,
                                    onCheckedChange = { isChecked ->
                                        categoryCheckedState[category] = isChecked
                                    }
                                )
                            },
                            onClick = {
                                categoryCheckedState[category] = !categoryCheckedState[category]!!
                            }
                        )
                    }
                }
            }
            ElevatedButton(
                onClick = { /* Handle button click */ }
            ) {
                Text("Priority")
            }
            ElevatedButton(onClick = { /* Handle button click */ }) {
                Text("Difficulty")
            }
        }

        LazyColumn(
            modifier = Modifier.weight(1f),
            contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp)
        ) {
            val groupedTasks = tasks.groupBy { it.category }

            categories.forEach { category ->
                if (categoryCheckedState[category] == true) {
                    stickyHeader {
                        Box(
                            modifier = Modifier
                                .fillMaxWidth()
                                .background(Color.LightGray)
                                .padding(8.dp)
                        ) {
                            Text(
                                text = category.name,
                                modifier = Modifier.padding(8.dp)
                            )
                        }
                    }
                    items(groupedTasks[category] ?: emptyList()) { task ->
                        Text(text = task.name, modifier = Modifier.padding(8.dp))
                    }
                }
            }
        }
    }
}

// 补充必要的数据类定义
data class Category(val name: String)
data class Task(val name: String, val category: Category, val priority: String, val difficulty: String)
关键说明
  • 状态持久化:通过remember的lambda初始化mutableStateMap,确保只有首次创建Composable时才会设置初始选中状态,后续重组不会覆盖已有状态
  • 逻辑一致性:MenuItem点击和Switch状态变化都统一修改categoryCheckedState,避免状态不一致问题
  • 代码简化:移除无用变量,让代码结构更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 14:57:56