我有一个刷卡删除,它绘制一个背景(很像收件箱应用程序),由ItemTouchHelper实现 - 通过覆盖onChilDraw方法并在提供的画布上绘制一个矩形:
ItemTouchHelper mIth = new ItemTouchHelper(
new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
remove(viewHolder.getAdapterPosition());
}
public boolean onMove(RecyclerView recyclerview, RecyclerView.ViewHolder v, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
View itemView = viewHolder.itemView;
Drawable d = ContextCompat.getDrawable(context, R.drawable.bg_swipe_item_right);
d.setBounds(itemView.getLeft(), itemView.getTop(), (int) dX, itemView.getBottom());
d.draw(c);
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
});
上面调用的remove方法在Adapter中:
public void remove(int position) {
items.remove(position);
notifyItemRemoved(position);
}
背景很好,但是当调用notifyItemRemoved时(根据Debugger先生的说法),RecyclerView首先删除我漂亮的绿色背景,然后将两个相邻的项目推到一起 .
我希望它保留背景,同时它(就像收件箱应用程序一样) . 有没有办法做到这一点?
3 回答
我有同样的问题,我不想介绍一个新的lib只是为了解决它 .
RecyclerView
没有删除你漂亮的绿色背景,它只是重绘自己,你的ItemTouchHelper
不再画画了 . 实际上它是绘图但是dX
是0并且从itemView.getLeft()
(它是0)绘制到dX
(它是0)所以你什么也看不见 . 它会在稍后再回来 .无论如何在行动画时回到背景:我无法在
ItemTouchHelper
和onChildDraw
中执行此操作 . 最后我不得不添加另一个项目装饰器来做到这一点 . 它遵循这些方针:此代码仅考虑动画的行,但您还应考虑下降的行 . 如果您滑动删除最后一行,上面的行将动画到该空间,就会发生这种情况 .
当我说你的ItemTouchHelper绘制的太多我的意思是:看起来
ItemTouchHelper
保留ViewHolder
的被删除的行,以防它们需要恢复 . 除了正在刷的VH之外,它还为那些VH调用onChildDraw
. 不确定此行为的内存管理含义,但我需要在onChildDraw
的开头进行额外检查,以避免绘制"fantom"行 .在你的情况下,它是从左= 0到右= 0绘制,所以你没有看到任何东西,但开销就在那里 . 如果你开始看到之前刷过的行描绘他们的背景,这就是原因 .
编辑:我去了这个,看到这个blog post和这个github repo .
我设法通过使用Wasabeefs's recyclerview-animators库来使其工作 .
我的ViewHolder现在扩展了库提供的AnimateViewHolder:
覆盖的函数实现与github上的recyclerview-animators自述文件相同 .
似乎有必要将ItemAnimator更改为自定义,并将removeDuration设置为0(或另一个低值 - 这是为了防止一些闪烁):
这不会导致任何问题,因为使用的正常(非滑动)移除动画是AnimateViewHolder中的动画 .
所有其他代码与问题中的代码保持一致 . 我还没有时间弄清楚这个内部工作原理,但是如果有人想这样做,请随时更新这个答案 .
更新:设置
recyclerView.getItemAnimator().setRemoveDuration(0);
实际上会破坏滑动的"rebind"动画 . 幸运的是,删除该行并在animateRemoveImpl中设置更长的持续时间(500适用于我)也解决了闪烁问题 .更新2:原来ItemTouchHelper.SimpleCallback使用ItemAnimator的动画持续时间,这就是上面的setRemoveDuration(0)打破滑动动画的原因 . 简单地将它的方法getAnimationDuration覆盖为:
解决了这个问题 .
只需更新适配器位置,然后删除动画即可