You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中ListAdapter调用submitList后RecyclerView滚动位置重置如何解决

问题解决方案

核心原因

闪烁和滚动位置重置问题的根源是DiffUtil.ItemCallback的实现逻辑错误,导致DiffUtil无法正确识别新旧列表的相同项,误判为整个列表发生了全量替换,触发了全局重绘。

修复步骤

1. 修正DiffCallback实现

将areItemsTheSame的引用相等判断替换为唯一ID判断,同时areContentsTheSame需要覆盖所有UI相关字段的校验:

companion object DiffCallback : DiffUtil.ItemCallback<Template>() {
    override fun areItemsTheSame(oldItem: Template, newItem: Template): Boolean {
        // 用唯一ID判断是否是同一个条目,而非引用相等
        return oldItem.id_template == newItem.id_template
    }
    override fun areContentsTheSame(oldItem: Template, newItem: Template): Boolean {
        // 所有在列表项中展示的字段都需要加入对比,确保仅内容变化时才触发条目刷新
        return oldItem.id_template == newItem.id_template
                && oldItem.title == newItem.title
                && oldItem.createTime == newItem.createTime
                // 按需补充其他业务使用的展示字段
    }
}

2. 可选:手动保留滚动位置

如果修正Diff后仍存在滚动位置偏移,可以在BindingAdapter中利用submitList的完成回调手动恢复滚动位置:

@BindingAdapter("listTemplate", "hirarki")
fun bindListTemplate(recyclerView: RecyclerView, data: List<Template>?, hirarki: Int) {
    val adapter = recyclerView.adapter as TemplateChiefAdapter
    val layoutManager = recyclerView.layoutManager as LinearLayoutManager
    // 提交前保存当前滚动位置
    val firstVisiblePos = layoutManager.findFirstVisibleItemPosition()
    val topOffset = layoutManager.getChildAt(0)?.top ?: 0
    // 提交列表,Diff计算完成后恢复位置
    adapter.submitList(data) {
        layoutManager.scrollToPositionWithOffset(firstVisiblePos, topOffset)
    }
}

3. 辅助优化减少闪烁

  • 给RecyclerView开启固定大小优化:在XML中给RecyclerView添加app:hasFixedSize="true",如果列表的整体尺寸不会随内容变化,这个配置可以避免不必要的重绘。
  • 确保列表项布局设置了明确的高度,避免RecyclerView重新测量条目导致的位置偏移。
  • 每次调用submitList时传入新的列表副本,不要复用旧列表对象修改后直接提交,否则ListAdapter会跳过Diff计算。

内容的提问来源于stack exchange,提问作者Space Colony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 14:39:00