Android DiffUtil更新RecyclerView如何仅增删条目不移动已有内容
解决方案
你当前的实现问题出在areItemsTheSame全局返回true的逻辑,DiffUtil会误判所有位置的条目为同一对象,导致计算出不符合预期的移动操作,无法满足「仅新增/移除条目、不移动已展示条目」的需求。
修正后的实现代码
fun notifyChanges(newListSize: Int) { val oldSize = tilesNumber // 直接取当前Adapter已有的条目数,避免外部变量状态不一致 val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() { override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { // 只有位置相同的条目判定为同一个,保证已有条目不会被移动 return oldItemPosition == newItemPosition } override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { // 已有条目内容无需更新,直接返回true即可 return true } override fun getOldListSize() = oldSize override fun getNewListSize() = newListSize }) tilesNumber = newListSize diff.dispatchUpdatesTo(this) }
实现逻辑说明
- 当
newListSize > 旧条目数时:DiffUtil会判定从oldSize到newListSize - 1的区间为新增条目,自动触发notifyItemRangeInserted回调,前面已展示的条目不会有任何变动 - 当
newListSize < 旧条目数时:DiffUtil会判定从newListSize到oldSize - 1的区间为待移除条目,自动触发notifyItemRangeRemoved回调,保留的前newListSize个条目位置完全不变 - 如果后续你需要支持条目内容更新,只需修改
areContentsTheSame的逻辑,加入对应位置的内容对比即可,不影响条目不移动的特性
原有调用逻辑无需修改,仍可正常使用:
mAdapter.notifyChanges(columnNumber * rowNumber)
内容的提问来源于stack exchange,提问作者Klariskao
相关产品推荐
相关产品推荐

