首页 > 解决方案 > 使用itemTouchViewer在Recyclerview中拖放不影响动画

问题描述

我在适配器类中实现 onDragDrop 方法。

 public boolean onDragDrop(int fromPosition, int toPosition) {
    Collections.swap(list, fromPosition, toPosition);
    notifyItemMoved(fromPosition, toPosition);
    if (fromPosition < toPosition) {
        notifyItemRangeChanged(fromPosition, list.size());
    } else {
        notifyItemRangeChanged(toPosition, list.size());
    }
    return true;
}

我面临的问题是在实现 onDragDrop 方法时,动画效果不好;在被替换之前有一丝元素。我知道对于拖放,只需 notifyItemMoved 方法就足够了,并且动画是完美的。我实现 notifyItemRangeChanged 的​​原因是拖放后,我希望数据得到刷新。

我浏览了很多 StackOverflow 帖子并尝试实施这些建议,但没有任何效果。谢谢你的帮助。

标签: javaandroidandroid-recyclerview

解决方案


尝试在您的notifyItemRangeChanged()调用中添加第三个参数。它实际上可以是任何对象,但我推荐它,Boolean.FALSE因为它不会占用任何额外的内存,并且因为“假”和“不要运行我不想要的动画”是一些相关的概念。

if (fromPosition < toPosition) {
    notifyItemRangeChanged(fromPosition, list.size(), Boolean.FALSE);
} else {
    notifyItemRangeChanged(toPosition, list.size(), Boolean.FALSE);
}

这应该起作用的原因与当您通知适配器项目已更改时整个 RecyclerView 系统所做的事情有关。该过程的一部分涉及DefaultItemAnimator,它必须决定是否重用旧的 ViewHolder 实例。你想要这个重复使用,但你没有得到它。

当您将第三个参数传递给 时notifyItemRangeChanged(),该第三个参数作为“有效负载”在系统中传递。DefaultItemAnimator是接收这个payload的系统的一部分,它根据这个payload是否存在来决定是否重用ViewHolders。

@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
        @NonNull List<Object> payloads) {
    return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}

在您当前的代码中,没有有效负载,因此不会重复使用 ViewHolders。这会导致“旧” ViewHolder 淡出和“新” ViewHolder 淡入的动画,看起来非常像闪烁。

当你添加第三个参数时,突然有一个有效载荷。同样,有效载荷是什么并不重要,只要它存在即可。现在您的 ViewHolder 可以重复使用,因此没有淡入/淡出动画。


推荐阅读