英文:
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("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 = { /* 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))
}
}
}
}
}
}
Thanks for any feedback <3
答案1
得分: 0
以下是您要翻译的代码部分:
categories.forEach { category ->
categoryCheckedState[category] = true
}
每次重新生成TaskPageLayout
时,此代码都会运行并将所有映射值设置为true
。
我假设您希望初始化映射时所有值都设置为true
,但不希望每次重新生成时都将它们设置为true
。
删除该部分并像这样初始化categoryCheckedState
:
val categoryCheckedState = remember {
mutableStateMapOf<Category, Boolean>().apply {
categories.forEach { category ->
this[category] = true
}
}
}
然后您就可以正常运行了:D
英文:
categories.forEach { category ->
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<Category, Boolean>().apply {
categories.forEach { category ->
this[category] = true
}
}
}
And you should be good to go
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论