我在使用notifyItemMoved()方法时遇到问题。似乎错误地显示了未移动的 View 。
我的 list 中有4个元素。我要做的是为第1项和第3项之间的交换设置动画。第1项和第3项可以正确交换,但是第2项显示第3项的内容!
因此,列表开始看起来像这样:

Item 0
Item 1
Item 2
Item 3
并结束像这样:
Item 0
Item 3
Item 3 <-- What the heck has this changed for?
Item 1
我的适配器由List mProductList支持。我调用以下代码:
public void sortBackingListUsingSortingList(List<ProductWrapper> newProductItems) {
    Log.e("", "Before:");
    for(ProductWrapper wrapper : mProductItems) wrapper.log();
    for(int i = 0; i < newProductItems.size(); i++) {
        ProductWrapper currentItem   = mProductItems.get(i);
        ProductWrapper correctItem   = newProductItems.get(i);

        if(!currentItem.equals(correctItem)) {
            // Item in wrong place
            int indexOfCorrectItem = getIndexOfItemInList(mProductItems, correctItem);
            Collections.swap(mProductItems, i, indexOfCorrectItem);
            notifyItemMoved(i, indexOfCorrectItem);
            Log.e("", "notifyItemMoved(" + i + ", " + indexOfCorrectItem+")");
            Log.e("", "After:");
            for(ProductWrapper wrapper : mProductItems) wrapper.log();
        }
    }
}
我还向onBindViewHolder添加了日志记录,以检查是否调用了我的 View 逻辑:
@Override
public void onBindViewHolder(HolderBasic holder, int position) {
    Log.e("", "onBindViewHolder(holder, " + position + ")");
    holder.fill(mProductItems.get(position));
}
我的日志如下所示:
09-02 14:39:17.853: Before:
09-02 14:39:17.853: Item 0
09-02 14:39:17.853: Item 1
09-02 14:39:17.853: Item 2
09-02 14:39:17.853: Item 3

09-02 14:39:17.854: notifyItemMoved(1, 3)

09-02 14:39:17.854: After:
09-02 14:39:17.854: Item 0
09-02 14:39:17.854: Item 3
09-02 14:39:17.854: Item 2
09-02 14:39:17.854: Item 1

09-02 14:39:17.867: onBindViewHolder(holder, 1)
09-02 14:39:17.874: onBindViewHolder(holder, 3)
如您所见,第2项完全没有理由更改,但现在确实如此。有人知道为什么吗?
编辑
我可以通过遍历整个适配器并在每个项目上调用notifyItemChanged()来解决上述问题。低效的解决方案不是很好的解决方案,但对用户而言是看不见的。

最佳答案

感谢@ david.mihola将我引到我做错了什么。

由于症状并未使问题变得显而易见,因此花了很长时间才弄清楚!

我正在这样做:

Collections.swap(mProductItems, i, indexOfCorrectItem);
notifyItemMoved(i, indexOfCorrectItem)

但是,我显然没有考虑notifyItemMoved()实际在做什么。它只是在通知适配器i项已移至indexOfCorrectItem ,而不是告诉适配器indexOfCorrectItem也已移至i

在幕后,它正在执行以下操作:
  • 将项目1移到3
  • 将2的位置移至1,以填补
  • 的空白
  • 将3处的值移至2以填补空白
  • notifyItemChanged(1);
  • notifyItemChanged(3);

  • 当然,上面的内容使项目3向下移动到项目2,而没有刷新的 View !是第4步和第5步通过使item1和item3正确显示而使item2不正确隐藏了问题!

    意识到这一点后,我尝试了以下代码:
    notifyItemMoved(indexOfCorrectItem, i);
    notifyItemMoved(i, indexOfCorrectItem);
    

    这样就可以按照正确的顺序排列列表,但是会缩短动画的播放时间。

    因此,我完全放弃了交换:
    mProductItems.remove(indexOfCorrectItem);
    mProductItems.add(i, correctItem);
    notifyItemMoved(indexOfCorrectItem, i);
    

    关于android - RecyclerView使用notifyItemMoved()破坏 View ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32354917/

    10-10 19:02