【问题标题】:Jetpack compose list wrong item selected after reordering or filteringJetpack compose list 在重新排序或过滤后选择了错误的项目
【发布时间】:2021-09-11 13:39:37
【问题描述】:

我有一个 ViewModel 可以生成这样的 StateFlow:

private val _profiles = MutableStateFlow<List<ProfileSnap>>(listOf())
val profiles: StateFlow<List<ProfileSnap>>
  get() = _profiles

值在另一个有趣的地方更新:

private fun loadProfiles() = viewModelScope.launch {
   _profiles.value = profileDao.getAll(profilesSearch, profilesSort)
}

最后,在 Compose 中列出所有值(这是我的代码的简化版本):

@Composable
fun SetContent(viewModel: ProfilesViewModel){
   val profiles = viewModel.profiles.collectAsState()
   LazyColumn(
      modifier = Modifier
         .fillMaxHeight()
   ) {
      itemsIndexed(items = profiles.value) { _, profile ->
         Text(
            text = "(${profile.profileId}) ${profile.label}",
            modifier = Modifier
            .pointerInput(Unit) {
               detectTapGestures(
                  onLongPress = {
                     Log.d(TAG, "onLongPress: ${profile.profileId}")
                  },
                  onTap = {
                     Log.d(TAG, "onTap: ${profile.profileId}")
                  },
               )
            }   
         ) 
      }
   }    
}

一开始,当我到达列表片段并单击一个元素时,我得到了正确的对应profileId。但是,当我应用过滤器或更改列表排序并调用 loadProfiles() 函数时:

  1. 列表会根据新过滤和/排序的配置文件正确更改
  2. 当我单击某个元素时,我得到了错误的 profileId,我似乎是以前的列表配置之一!

我做错了什么?配置文件不是最新的?但如果它们没有更新,为什么列表是“图形”正确的?这里会发生什么:

(1) A
-----
(2) B   
-----
(3) C   <== CLICK - onTap: 3 / LONGPRESS - onLongPress: 3

更改排序顺序:

(3) C
-----
(2) B   
-----
(1) A   <== CLICK - onTap: 3 [should has been 1] / LONGPRESS - onLongPress: 3 [should has been 1]

非常感谢

【问题讨论】:

    标签: android kotlin android-jetpack-compose kotlin-flow


    【解决方案1】:

    您可以查看official doc

    默认情况下,每个项目的状态都是针对列表中项目的位置键控。但是,如果数据集发生更改,这可能会导致问题,因为更改位置的项目实际上会丢失任何记住的状态。如果您想象LazyRowLazyColumn 中的场景,如果行更改项目位置,则用户将失去其在行内的滚动位置。

    为了解决这个问题,您可以为每个项目提供一个稳定且唯一的密钥,为 key 参数提供一个块。 提供稳定的密钥可以使项目状态在数据集更改时保持一致

    LazyColumn() {
          items(
                items = profiles.value,
                key = { profile ->
                        // Return a stable + unique key for the item
                        profile.profileId
                    }
          ) { profile ->
             //....
          }
       } 
    

    【讨论】:

    • 谢谢加布里埃尔!这就是问题所在,我错过了!
    • @Gattaccio7 你需要import androidx.compose.foundation.lazy.items 才能通过列表使用items 而不是count
    • @PhilipDukhov 很好,它就像一个魅力,谢谢!我必须在 Gradle 文件中导入 Compose 1.02。
    【解决方案2】:

    按照 Gabriele 的提示,这是一个工作版本(我找不到 items 函数的相同签名):

    LazyColumn() {
        items(
          count = profiles.value.size,
          key = { index -> profiles.value[index].profileId }
        ) { index ->
          val profile = profiles.value[index]
          Item(profile)
          Line()
        }
      }
    

    【讨论】:

    • 你需要import androidx.compose.foundation.lazy.items才能使用Gabriele的答案,所以你可以删除这个
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多