Jetpack Compose 惰性列单选

8
我从服务器获取数据并在列表中显示,每个项目都可以通过一次单击选择以显示按钮,但我无法关闭它,只能打开它。
这是列表类的项目。
data class Task(
    val deviceName: String,
    val deviceId: String,
    var selected :Boolean= Boolean,
)

这是数据类。

data class TaskStatus(
    val taskList: SnapshotStateList<Task>  = SnapshotStateList(),
    val selectedNumber: Int = -1,
)

我的ViewModel

private val _status = MutableStateFlow(TaskStatus())
val status = _status.asStateFlow()

fun getList(){
  ...
  for(item in result){
    _status.value.taskList.add(task)
  }
}
fun selectTask(task: Task) {
  val list = _status.value.taskList
  val selectNumber = _status.value.selectedNumber
  val newSelectNumber = list.indexOf(task)
    if (newSelectNumber != selectNumber) {
      if (selectNumber != -1) {
        list[selectNumber].selected.value = false
      }
    }
  task.selected.value = !task.selected.value
  _status.update { it.copy(selectedNumber = newSelectNumber) }
}

我的 LazyColumn

...
LazyColumn(
  modifier = Modifier
    .fillMaxWidth()
    .weight(1F),
  verticalArrangement = Arrangement.spacedBy(11.dp), contentPadding = PaddingValues(16.dp)
) {
  items(
    taskStatus.taskList,
    key = { it.deviceId }) { task ->
      Item(task)
    }
}

@Compose
fun Item(task:Task){
  Column(){
    Text(text = task.name)
    Text(text = task.deviceId)
    if(task.selected){
      Botton()
    }
  }
}

我只能显示按钮,但不能隐藏它。

提前感谢。

1个回答

1

我无法直接编译您的代码,因此我尝试制作自己的实现。 我添加了一个回调函数,它将从您的任务项中触发

您的TaskList组合内容

@Composable
fun TaskList(
    taskList: SnapshotStateList<Task>,
    onSelected: (Task) -> Unit
) {
    LazyColumn(
        modifier = Modifier
            .fillMaxWidth(),
        verticalArrangement = Arrangement.spacedBy(11.dp), contentPadding = PaddingValues(16.dp)
    ) {
        items(
            taskList,
            key = { it.deviceId }) { task ->
            Item(task) {
                onSelected(it)
            }
        }
    }
}

您的TaskItem可组合部件
@Composable
fun Item(
    task:Task,
    onSelected: (Task) -> Unit
){
    Column(
        modifier = Modifier.clickable {
            onSelected(task) // selection callback
        }
    ){
        Text(text = task.deviceName)
        Text(text = task.deviceId)
        if(task.selected) {

            Box(modifier = Modifier
                .fillMaxWidth()
                .height(100.dp)
                .background(Color.Red)) {
            }
        }
    }
}

我嘲笑了一个VieModel

class TaskStateHolder {
    private val _status = MutableStateFlow( TaskStatus (
        taskList = mutableStateListOf(
            Task(
                deviceName = "Device 1",
                deviceId = "Device 1 ID"
            ),
            Task(
                deviceName = "Device 2",
                deviceId = "Device 2 ID"
            ),
            Task(
                deviceName = "Device 3",
                deviceId = "Device 3 ID"
            ),
            Task(
                deviceName = "Device 4",
                deviceId = "Device 4 ID"
            ),
        )
    ))

    val status = _status.asStateFlow()

    fun selectTask(task: Task) {
        _status.update {
            val list = it.taskList
            val newSelectNumber = list.indexOf(task)
            val iterator = list.listIterator()
            while (iterator.hasNext()) {
                val obj = iterator.next()
                if (task.deviceId == obj.deviceId) {
                    iterator.set(task.copy(selected = true))
                } else {
                    iterator.set(obj.copy(selected = false))
                }
            }

            it.copy(selectedNumber = newSelectNumber)
        }
    }
}

我修改了你的selectedTask函数,使用列表的迭代器一次性执行了_status为flow的更新操作。

在某个地方(例如“TaskScreen”)的使用方法:

val tasks by stateHolder.status.collectAsState()
    Column {
        TaskList(tasks.taskList) {
            stateHolder.selectTask(it)
        }
    }

enter image description here


谢谢你的回答。我尝试了你的方法,但是很抱歉我没有表达清楚。我的意思是,数据已经改变了,但是显示没有改变。我甚至无法使用你的方法。我可以展开每个项目,但如果你想展开其中一个,其他项目将被关闭。 - 卡尔斯路西法
我想一次只打开一个项目。 - 卡尔斯路西法
我尝试使用您发布的可用代码进行了自己的实现,请查看更新的答案和显示单选内容的 .gif。 - z.g.y
非常感谢您的回答。我已经完成了我需要的功能,并优化了您给我的代码。我将 selectedNumber 改为 selectId - 卡尔斯路西法
再次感谢,我有一些小问题。 viewmodel的数据会保留多久?如果创建了两个相同的viewmodel,数据会相同吗?也许我应该发送另一个问题。 - 卡尔斯路西法

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接