使用Switch在DropDownMenu中(关闭菜单时开关状态未保存) – Jetpack Compose

huangapple go评论53阅读模式
英文:

Using Switch in DropDownMenu (Switch toggled state not saving when menu closed) - Jetpack Compose

问题

我正在尝试使用Material 3和Jetpack Compose构建一个用于Android的待办事项应用程序。我试图创建一个下拉菜单,允许用户在屏幕上看到哪些“类别”任务。我正在使用Switch来实现这个功能。

当我点击切换关闭一个类别时,它确实从屏幕上移除了。然而,当我关闭下拉菜单时,该类别会重新出现。我是一个非常初学者,我很难理解如何在关闭菜单时保存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>() }
    categories.forEach { category ->
        categoryCheckedState[category] = true
    }

    var selectedCategories by remember { mutableStateOf(emptyList<Category>()) }

    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]!!
                                selectedCategories = if (category in selectedCategories) {
                                    selectedCategories - category
                                } else {
                                    selectedCategories + category
                                }
                            },
                            modifier = Modifier.clickable(
                                interactionSource = remember { MutableInteractionSource() },
                                indication = null
                            ) {}
                        )
                    }
                }
            }
            ElevatedButton(
                onClick = { /* 处理按钮点击 */ }
            ) {
                Text("Priority")
            }
            ElevatedButton(onClick = { /* 处理按钮点击 */ }) {
                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))
                    }
                }
            }
        }
    }
}

感谢任何反馈 <3

英文:

I'm trying to build a to-do app for Android using Material 3 & Jetpack Compose. I'm trying to create a drop down menu that allows users to filter which "Category" of tasks they see on the screen. I'm using Switch to do this.
Drop down menu w/ Switch

When I click to toggle a category off, it does get removed from the screen. However, when I close the drop down menu the category reappears. I'm very much a beginner, and I'm having a hard time understanding how to save the Switch state when the menu is closed. Any help is much appreciated!

Here is my current code:

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TaskPageLayout(
contentPadding: PaddingValues = PaddingValues()
) {
val categories = listOf(
Category(&quot;Home&quot;),
Category(&quot;Work&quot;),
Category(&quot;Chores&quot;)
)
val tasks = listOf(
Task(&quot;Task 1&quot;, categories[0], &quot;High&quot;, &quot;Easy&quot;),
Task(&quot;Task 2&quot;, categories[1], &quot;Medium&quot;, &quot;Medium&quot;),
Task(&quot;Task 3&quot;, categories[2], &quot;Low&quot;, &quot;Hard&quot;),
Task(&quot;Task 4&quot;, categories[0], &quot;High&quot;, &quot;Easy&quot;)
)
var expanded by remember { mutableStateOf(false) }
val categoryCheckedState = remember { mutableStateMapOf&lt;Category, Boolean&gt;() }
categories.forEach { category -&gt;
categoryCheckedState[category] = true
}
var selectedCategories by remember { mutableStateOf(emptyList&lt;Category&gt;()) }
Column(
modifier = Modifier
.fillMaxSize()
.padding(contentPadding)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceAround
) {
Box {
ElevatedButton(onClick = { expanded = true }) {
Text(&quot;Category&quot;)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
categories.forEach { category -&gt;
DropdownMenuItem(
text = { Text(category.name) },
trailingIcon = {
Switch(
modifier = Modifier
.semantics {
contentDescription =
&quot;Switch to choose which categories to view&quot;
},
checked = categoryCheckedState[category] ?: false,
onCheckedChange = { isChecked -&gt;
categoryCheckedState[category] = isChecked
}
)
},
onClick = {
categoryCheckedState[category] = !categoryCheckedState[category]!!
selectedCategories = if (category in selectedCategories) {
selectedCategories - category
} else {
selectedCategories + category
}
},
modifier = Modifier.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null
) {}
)
}
}
}
ElevatedButton(
onClick = { /* Handle button click */ }
) {
Text(&quot;Priority&quot;)
}
ElevatedButton(onClick = { /* Handle button click */ }) {
Text(&quot;Difficulty&quot;)
}
}
LazyColumn(
modifier = Modifier.weight(1f),
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 16.dp)
) {
val groupedTasks = tasks.groupBy { it.category }
categories.forEach { category -&gt;
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 -&gt;
Text(text = task.name, modifier = Modifier.padding(8.dp))
}
}
}
}
}
}

Thanks for any feedback <3

答案1

得分: 0

以下是您要翻译的代码部分:

categories.forEach { category -&gt;
categoryCheckedState[category] = true
}

每次重新生成TaskPageLayout时,此代码都会运行并将所有映射值设置为true
我假设您希望初始化映射时所有值都设置为true,但不希望每次重新生成时都将它们设置为true

删除该部分并像这样初始化categoryCheckedState

val categoryCheckedState = remember {
mutableStateMapOf&lt;Category, Boolean&gt;().apply {
categories.forEach { category -&gt;
this[category] = true
}
}
}

然后您就可以正常运行了:D

英文:
categories.forEach { category -&gt;
categoryCheckedState[category] = true
}

Every time TaskPageLayout is recomposed this code runs and sets all your map values to true.
I assume that you want to initiate the map with all of the values set to true, but not set them to true every time a recomposition occurs.

Remove that segment and initiate categoryCheckedState like this:

val categoryCheckedState = remember {
mutableStateMapOf&lt;Category, Boolean&gt;().apply {
categories.forEach { category -&gt;
this[category] = true
}
}
}

And you should be good to go 使用Switch在DropDownMenu中(关闭菜单时开关状态未保存) – Jetpack Compose

huangapple
  • 本文由 发表于 2023年5月17日 10:17:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/76268154.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定