kotlin 更新一行时,LazyColumn会重新组合所有行

yeotifhr  于 2023-06-24  发布在  Kotlin
关注(0)|答案(1)|浏览(172)

我正在学习作曲,作为一个练习,我试图显示一个倒计时器列表。一个按钮将添加一个新的计时器到列表中,然后对于该列表中的每个计时器,lazycolumn将显示一行,其中包含显示倒计时时间的文本和开始倒计时的按钮。
在这里,我添加了三个计时器到列表中,它们都显示得很好:

然后,当我开始倒计时时,所有其他行都会更新,即使它们没有被更改:

我的视图模型:

data class MyClass(val text: String, val isClickable: Boolean)

class VM : ViewModel() {
    val myList = mutableStateListOf<MyClass>()

    fun addTimer() {
        myList.add(myList.size, MyClass("0", true))
    }

    fun changeText(index: Int, tempo: String) {
        myList[index] = myList[index].copy(text = tempo)
    }

    fun changeIsClickable(index: Int, click: Boolean) {
        myList[index] = myList[index].copy(isClickable = click)
    }
}

我的可组合屏幕:

val viewModel: VM by viewModels()
(...)
@Composable
fun MainScreen(viewModel: VM) {
    val scope = CoroutineScope(Dispatchers.Main)
    Column(verticalArrangement = Arrangement.spacedBy(15.dp)) {
        Row() {
                Button(onClick = { viewModel.addTimer() }
                ) {
                    Text(text = "Add Timer")
                }
        }
        LazyColumn {
            itemsIndexed(viewModel.myList) { index, list ->
                Row(modifier = Modifier.border(8.dp, randomColor())) {
                    Text(
                        text = list.text, modifier = Modifier
                            .padding(20.dp)
                    )
                    Button(
                        enabled = list.isClickable,
                        onClick = {
                            viewModel.changeIsClickable(index, false)
                            var currTime = Calendar.getInstance().timeInMillis
                            val endTime =
                                currTime + (7000L..20000L).random()  //random between 7 and 20
                            scope.launch {
                                while (endTime > currTime) {
                                    delay(100)
                                    val timeTemporary =
                                        ((endTime - currTime) / 1000).toString() + "\n" + "Secs"
                                    viewModel.changeText(index, timeTemporary)
                                    currTime = Calendar.getInstance().timeInMillis
                                }
                                viewModel.changeText(index, "Done")
                                viewModel.changeIsClickable(index, true)
                            }
                        }) {
                        Text(text = "Start")
                    }
                }
            }
        }
    }
}

我尝试了很多建议,比如this onethis one(因此使用彩色边框来检查重组),但我无法使未更改的行不更新。我错过了什么?我怎样才能阻止lazycolumn在不应该更新的时候进行更新?

pu3pd22g

pu3pd22g1#

将项目添加到单独的组合项中。每个可组合函数是否可跳过取决于可组合函数的参数。在本例中,您将索引和项作为参数。当计时器不运行时,这两个参数都不会改变,并且因为这两个参数都不会改变,所以在重组过程中将跳过可组合对象。

@Composable
fun StackOverflowScreen() {
    Column(verticalArrangement = Arrangement.spacedBy(15.dp)) {
        Row() {
            Button(onClick = { viewModel.addTimer() }
            ) {
                Text(text = "Add Timer")
            }
        }
        LazyColumn {
            itemsIndexed(viewModel.myList) { index, list ->
                TimerItem(index, list)
            }
        }
    }
}

@Composable
private fun TimerItem(index: Int, list: MyClass) {
    val scope = CoroutineScope(Dispatchers.Main)
    Row(modifier = Modifier.border(8.dp, randomColor())) {
        Text(
            text = list.text, modifier = Modifier
                .padding(20.dp)
        )
        Button(
            enabled = list.isClickable,
            onClick = {
                viewModel.changeIsClickable(index, false)
                var currTime = Calendar.getInstance().timeInMillis
                val endTime =
                    currTime + (7000L..20000L).random()  //random between 7 and 20
                scope.launch {
                    while (endTime > currTime) {
                        delay(100)
                        val timeTemporary =
                            ((endTime - currTime) / 1000).toString() + "\n" + "Secs"
                        viewModel.changeText(index, timeTemporary)
                        currTime = Calendar.getInstance().timeInMillis
                    }
                    viewModel.changeText(index, "Done")
                    viewModel.changeIsClickable(index, true)
                }
            }) {
            Text(text = "Start")
        }
    }
}

相关问题