Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jetpack Compose Lazy Column single selection

I'm getting data from the server and displaying it in the list, each item can be selected with one click to display the button, but I cannot close it, I can only open it.

This is item of list class

data class Task(
    val deviceName: String,
    val deviceId: String,
    var selected :Boolean= Boolean,
)

this is data class

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

My 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) }
}

My 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()
    }
  }
}

I can only show but not hide the button

Thank you in advance.

like image 846
卡尔斯路西法 Avatar asked Jul 03 '26 18:07

卡尔斯路西法


1 Answers

I can't compile your code directly so I tried to make my own implementation. I added a callback which will be triggered from your Task Item

Your TaskList composable

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

Your TaskItem Composable

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

And I mocked a 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)
        }
    }
}

I modified your selectedTask function, executing _status flow udpates in a single pass using the list's iterator.

Usage somewhere outside (e.g "TaskScreen")

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

enter image description here

like image 109
z.g.y Avatar answered Jul 06 '26 08:07

z.g.y



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!