Jetpack Compose 复选框未显示已更改状态
Jetpack Compose Checkbox Not Showing Changed State
我有一个专业列表,用户将从中检查。在用户对他们的选择感到满意后,我将收集所选复选框的信息并将这些专业保存在用户的个人资料中。
但是,当我点击任何复选框时,视图模型中的状态会发生变化,但复选框仍未选中。
专业列表
@Composable
fun SpecialtyList(
viewModel: SpecialtyListViewModel = hiltViewModel(),
navController: NavController
) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
item {
viewModel.specialtyList.value.forEach { specialty ->
Row(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = specialty.isSelected,
onCheckedChange = {
specialty.isSelected = it
},
colors = CheckboxDefaults.colors(MaterialTheme.colors.primary)
)
Text(
text = specialty.name,
modifier = Modifier
.padding(horizontal = 10.dp)
)
}
}
}
}
}
专业视图模型
@HiltViewModel
class SpecialtyListViewModel @Inject constructor() : ViewModel() {
// HARD-CODED PROPERTIES
val specialtyList = mutableStateOf(
mutableListOf(
Specialty(name = "Emergency Medicine", isSelected = false),
Specialty(name = "Forensic Medicine", isSelected = false),
Specialty(name = "General Practitioner", isSelected = false)
)
}
专业模型
data class Specialty(
val name: String,
var isSelected: Boolean
)
这显然不是 Compose 的工作方式。在文档中阅读更多内容,但目前,修复方法是用此
替换现有的 VM 实现
@HiltViewModel
class SpecialtyListViewModel @Inject constructor() : ViewModel() {
// HARD-CODED PROPERTIES
val specialtyList = mutableStateListOf(
Specialty(name = "Emergency Medicine", isSelected = false),
Specialty(name = "Forensic Medicine", isSelected = false),
Specialty(name = "General Practitioner", isSelected = false)
)
}
您不能在对 mutableStateOf
的调用中包装任何内容并期望它触发重组。看到这个问题:Create Custom MutableState<T> Holders
编辑:根据下面@Philip 对您的 post 的评论,我注意到您也错误地实施了 LazyColumn
。您必须将每个元素放在单独的 item
中,以便列有效地缓存和丢弃每个需要的元素。
@Composable
fun SpecialtyList(
viewModel: SpecialtyListViewModel = hiltViewModel(),
navController: NavController
) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
viewModel.specialtyList.value.forEach { specialty ->
item{
Row(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = specialty.isSelected,
onCheckedChange = {
specialty.isSelected = it
},
colors = CheckboxDefaults.colors(MaterialTheme.colors.primary)
)
Text(
text = specialty.name,
modifier = Modifier
.padding(horizontal = 10.dp)
)
}
}
}
}
}
这是一个小的交换。您还可以利用其他方式来实现这一点,例如,使用 items
块。
为了mutableStateOf
触发重组,应该更新容器值,例如specialtyList = newValue
.
它无法知道您更改了其中一个内部对象。
一般来说,data class
是一个很好的工具,可以在函数式编程中不可变地使用。如果你不会在其中使用 var
,你将排除很多错误。
如果您的情况看起来更干净,请使用 mutableStateListOf
。在您的视图模型中:
private val _specialtyList = mutableStateListOf(
Specialty(name = "Emergency Medicine", isSelected = false),
Specialty(name = "Forensic Medicine", isSelected = false),
Specialty(name = "General Practitioner", isSelected = false)
)
val specialtyList: List<Specialty> = _specialtyList
fun setSpecialtySelectedAtIndex(index: Int, isSelected: Boolean) {
_specialtyList[index] = _specialtyList[index].copy(isSelected = isSelected)
}
像这样从您的可组合项中使用它:
viewModel.specialtyList.value.forEachIndexed { i, specialty ->
// ...
onCheckedChange = {
viewModel.setSpecialtySelectedAtIndex(i, it)
},
}
您可以在 documentation, including this youtube video 中找到有关 Compose 状态的更多信息,其中解释了基本原则。
我有一个专业列表,用户将从中检查。在用户对他们的选择感到满意后,我将收集所选复选框的信息并将这些专业保存在用户的个人资料中。
但是,当我点击任何复选框时,视图模型中的状态会发生变化,但复选框仍未选中。
专业列表
@Composable
fun SpecialtyList(
viewModel: SpecialtyListViewModel = hiltViewModel(),
navController: NavController
) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
item {
viewModel.specialtyList.value.forEach { specialty ->
Row(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = specialty.isSelected,
onCheckedChange = {
specialty.isSelected = it
},
colors = CheckboxDefaults.colors(MaterialTheme.colors.primary)
)
Text(
text = specialty.name,
modifier = Modifier
.padding(horizontal = 10.dp)
)
}
}
}
}
}
专业视图模型
@HiltViewModel
class SpecialtyListViewModel @Inject constructor() : ViewModel() {
// HARD-CODED PROPERTIES
val specialtyList = mutableStateOf(
mutableListOf(
Specialty(name = "Emergency Medicine", isSelected = false),
Specialty(name = "Forensic Medicine", isSelected = false),
Specialty(name = "General Practitioner", isSelected = false)
)
}
专业模型
data class Specialty(
val name: String,
var isSelected: Boolean
)
这显然不是 Compose 的工作方式。在文档中阅读更多内容,但目前,修复方法是用此
替换现有的 VM 实现@HiltViewModel
class SpecialtyListViewModel @Inject constructor() : ViewModel() {
// HARD-CODED PROPERTIES
val specialtyList = mutableStateListOf(
Specialty(name = "Emergency Medicine", isSelected = false),
Specialty(name = "Forensic Medicine", isSelected = false),
Specialty(name = "General Practitioner", isSelected = false)
)
}
您不能在对 mutableStateOf
的调用中包装任何内容并期望它触发重组。看到这个问题:Create Custom MutableState<T> Holders
编辑:根据下面@Philip 对您的 post 的评论,我注意到您也错误地实施了 LazyColumn
。您必须将每个元素放在单独的 item
中,以便列有效地缓存和丢弃每个需要的元素。
@Composable
fun SpecialtyList(
viewModel: SpecialtyListViewModel = hiltViewModel(),
navController: NavController
) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
viewModel.specialtyList.value.forEach { specialty ->
item{
Row(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = specialty.isSelected,
onCheckedChange = {
specialty.isSelected = it
},
colors = CheckboxDefaults.colors(MaterialTheme.colors.primary)
)
Text(
text = specialty.name,
modifier = Modifier
.padding(horizontal = 10.dp)
)
}
}
}
}
}
这是一个小的交换。您还可以利用其他方式来实现这一点,例如,使用 items
块。
为了mutableStateOf
触发重组,应该更新容器值,例如specialtyList = newValue
.
它无法知道您更改了其中一个内部对象。
一般来说,data class
是一个很好的工具,可以在函数式编程中不可变地使用。如果你不会在其中使用 var
,你将排除很多错误。
如果您的情况看起来更干净,请使用 mutableStateListOf
。在您的视图模型中:
private val _specialtyList = mutableStateListOf(
Specialty(name = "Emergency Medicine", isSelected = false),
Specialty(name = "Forensic Medicine", isSelected = false),
Specialty(name = "General Practitioner", isSelected = false)
)
val specialtyList: List<Specialty> = _specialtyList
fun setSpecialtySelectedAtIndex(index: Int, isSelected: Boolean) {
_specialtyList[index] = _specialtyList[index].copy(isSelected = isSelected)
}
像这样从您的可组合项中使用它:
viewModel.specialtyList.value.forEachIndexed { i, specialty ->
// ...
onCheckedChange = {
viewModel.setSpecialtySelectedAtIndex(i, it)
},
}
您可以在 documentation, including this youtube video 中找到有关 Compose 状态的更多信息,其中解释了基本原则。