【问题标题】:Jetpack Compose Checkbox Not Showing Changed StateJetpack Compose 复选框未显示更改状态
【发布时间】:2021-11-20 14:42:05
【问题描述】:

我有一个专业列表供用户查看。在用户对他们的选择感到满意后,我将收集所选复选框的信息并将这些专业保存在用户的个人资料中。

但是,当我点击任何复选框时,视图模型中的状态会发生变化,但复选框仍处于未选中状态。

专业列表

@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
)

【问题讨论】:

  • 现在你的LazyColumn 并不懒惰,因为你在一个item 中显示所有行。相反,您可以使用items(viewModel.specialtyList.value)itemsIndexed(viewModel.specialtyList.value)(因为根据我的回答您需要索引)。

标签: android android-jetpack-compose android-checkbox


【解决方案1】:

为了让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 中找到有关 Compose 中状态的更多信息,包括解释基本原则的 this youtube video

【讨论】:

    【解决方案2】:

    这显然不是 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 下面对您帖子的评论,我注意到您也错误地实施了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 块。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-08
      • 2022-11-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-04
      • 2021-04-26
      • 2015-11-28
      • 1970-01-01
      相关资源
      最近更新 更多