RecyclerView动画结束后如何正确更新列表项内容?
问题解决:RecyclerView滑动删除后条目显示异常
问题分析
滑动删除前置条目后,屏幕末尾的条目TextView无法正确显示内容,核心原因在于:
- RecyclerView复用机制+通知不完整:删除条目后,后续条目的位置发生变更,但仅调用
notifyItemRemoved只会触发删除动画,不会通知后续条目重新绑定数据,导致复用的ViewHolder未更新内容。 - Swipe绘制逻辑冗余:
SwipeToDeleteCallback中重复调用super.onChildDraw,可能导致画布绘制残留,干扰View正常显示。
解决方案
1. 修复适配器的通知逻辑
修改DictionaryAdapter的removeEntry方法,在删除条目后,通知后续所有条目位置更新并重新绑定:
public void removeEntry(int position) { entries.remove(position); notifyItemRemoved(position); // 通知删除位置之后的所有条目重新绑定数据 notifyItemRangeChanged(position, entries.size() - position); }
2. 清理Swipe绘制逻辑中的冗余代码
修改SwipeToDeleteCallback的onChildDraw方法,移除重复的super.onChildDraw调用,避免画布绘制异常:
@Override public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { View itemView = viewHolder.itemView; int itemHeight = itemView.getHeight(); boolean isCancelled = dX == 0 && !isCurrentlyActive; if (isCancelled) { clearCanvas(c, itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom()); super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); return; } background.setColor(backgroundColor); background.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom()); background.draw(c); int deleteIconTop = itemView.getTop() + (itemHeight - intrinsicHeight) / 2; int deleteIconMargin = (itemHeight - intrinsicHeight) / 2; int deleteIconLeft = itemView.getRight() - deleteIconMargin - intrinsicWidth; int deleteIconRight = itemView.getRight() - deleteIconMargin; int deleteIconBottom = deleteIconTop + intrinsicHeight; deleteDrawable.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom); deleteDrawable.draw(c); // 仅保留一次父类绘制调用 super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); }
3. 确保ViewHolder绑定位置的准确性
在onBindViewHolder中使用holder.getAdapterPosition()获取最新位置,避免复用导致的位置错位:
@Override public void onBindViewHolder(DictionaryAdapter.ViewHolder holder, int position) { // 获取当前ViewHolder对应的最新adapter位置 int adapterPosition = holder.getAdapterPosition(); if (adapterPosition == RecyclerView.NO_POSITION) { return; } Entry entry = entries.get(adapterPosition); holder.wordRussianTextView.setText(entry.getWord(Entry.LANGUAGE.RUSSIAN)); holder.wordHebrewTextView.setText(entry.getWord(Entry.LANGUAGE.HEBREW)); holder.progressBar.setProgress(entry.getProgress()); Log.e("onBindViewHolder", "New item:"); Log.e("onBindViewHolder", "russian : " + holder.wordRussianTextView.getText()); Log.e("onBindViewHolder", "hebrew : " + holder.wordHebrewTextView.getText()); Log.e("onBindViewHolder", "--------------------------------"); }
原理说明
notifyItemRangeChanged会触发删除位置之后的所有条目重新调用onBindViewHolder,确保复用的ViewHolder更新到正确的数据。- 清理冗余的
super.onChildDraw调用后,画布绘制逻辑更清晰,避免残留的绘制内容覆盖正常的View显示。 - 使用
getAdapterPosition可以获取ViewHolder当前在Adapter中的真实位置,规避复用场景下的位置参数失效问题。
内容的提问来源于stack exchange,提问作者Serafim Dmitriev
相关产品推荐
相关产品推荐

