LazyColumn 项目互斥

Posted

技术标签:

【中文标题】LazyColumn 项目互斥【英文标题】:LazyColumn items mutual exclusive 【发布时间】:2021-12-08 21:14:45 【问题描述】:

假设我在LazyColumn 中有一个项目列表,它们都可以被选中。如何确保当一个项目被选中时,其他项目被取消选择(因此一次只能选择一项)?

我在考虑interactionSource,但我不确定如何使用它。

【问题讨论】:

这取决于你如何存储选择的状态,请添加一些代码。 【参考方案1】:

我会将此逻辑提取到 ViewModel 中,您的项目是一个特定的 UIModel,其中包含项目的当前数据 + 状态,包含 isSelected 状态。

例如:

data class YourUiModel(val id: Long, val isSelected: Boolean = false, ...)

private val _items = MutableStateFlow(emptyList<YourUiModel>())
val items: StateFlow<List<YourUiModel>>
    get() = _items
    
private fun changeSelectionTo(uiModel: YourUiModel) 
        _items.value = items.value.map  it.copy(isSelected = it.id == uiModel.id) 


...

【讨论】:

【参考方案2】:

您可以尝试使用记住...

@Composable
fun MyComposeList(data: List<MyItemData>,...) 
    val (selectedItem, setSelectedItem) = remember  mutableStateOf(null // or maybe data.first()  // remember current selected by state delegate

    lazyColumn()  // your lazy column
       items (data)  item -> // item = each item
          // your compose item view
          MyComposeItemView (
              data = item,  // pass data by each item
              isSelected = data == selectedItem // set is item selected by default
          ) 
              // on item click
              setSelectedItem(it)
           
       
    


@Composable
fun MyComposeItemView(
        data: MyItemData, 
        isSelected: Boolean, 
        onSelect: (MyItemData) -> Unit = ) 
   
   // here set item selected state = isSelected maybe change color or something

  // assume we have box as single item
  Box(Modifier.clickable 
     onSelect(data) // cal on click function and pass current data as parameter
  )

【讨论】:

【参考方案3】:

只存储一个变量来保存所选变量的索引

var sel by mutableStateOf(0)

现在,如果您在 Composables 中声明它,您可能希望在此处使用 remember,但我强烈建议将其存储在视图模型中。一个简单的例子是

class VM: ViewModel()
 var sel by mutableStateOf(0) //Assuming 0 is selected initially, change it to -1 if you please

 //Create a setter optionally, for state-hoisting
 fun setSel(index: Int)
   sel = index
 

在 MainActivity 中,

class MainActivity
 val vm by viewmodels<VM>()
 setContent
  MySelectableList(
     list = ...,
     selected = vm.sel,
     onSelectionChange = vm::setSel // Just pass the viewmodel if you did not create the setter
   )
 

 @Composable
 fun MySelectableList(
    list: List<Any>,
    selected: Int,
    onSelectionChange: (int) -> Unit // or vm, if you did not create the setter
  )
     list.forEachIndexed index, item ->
       // Now create this Composable yourself
       ItemComposable(
          isSelected = index == selected,
          onClick =  onSelectionChange(index)  // Just focus and have a look at what's happening here
       )
     
  

我在这里使用状态提升,请阅读this 以供参考。如果您还没有,请务必参加此代码实验室

如果您之前将 sel 的初始值设置为 -1,则需要进行额外检查。完全理解流经这里的代码。

【讨论】:

以上是关于LazyColumn 项目互斥的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Visual Studio 2010 中使用互斥锁

用于 Windows 的 C++ 互斥锁

FreeRTOS入门(03):队列信号量互斥量

使用互斥锁调节两个进程之间的 IPC

RTOS 任务间互斥的问题

RTOS 任务间互斥的问题