本文介绍了RecyclerView 使用 notifyItemMoved() 破坏视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用 notifyItemMoved() 方法时遇到问题.它似乎错误地显示了未移动的视图.

I'm having a problem with using the notifyItemMoved() method. It seems to be incorrectly displaying unmoved views.

我的列表中有 4 个元素.我想要做的是动画项目 1 和项目 3 之间的交换.项目 1 和 3 正确交换,但项目 2 显示项目 3 的内容!

My list has 4 element in it. What I want to do is animate a swap between item 1 and item 3. Items 1 and 3 swap correctly, but item 2 displays what was at item 3!

所以列表开始看起来像这样:

So the list starts off looking something like this:

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 支持.我调用以下代码:

My adapter is backed by a List mProductList. I call the following code:

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 添加了日志记录,以检查是否正在调用我的视图逻辑:

I've also added logging to onBindViewHolder to check if my view logic is being called:

@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 项根本没有理由更改其显示 - 然而,确实如此.有人知道为什么吗?

As you can see, no reason for Item 2 to have change it's display at all - and yet, it does. Anybody know why?

编辑

我可以通过遍历整个适配器并在每个项目上调用 notifyItemChanged() 来绕过上面的问题.效率低下,不是一个好的解决方案,但对用户不可见.

I can get around above by looping through the entire adapter and calling notifyItemChanged() on every item. Inefficient and not a good solution, but is invisible to the user.

推荐答案

感谢@david.mihola 引导我解决我做错的地方.

Thank you to @david.mihola for leading me to what I'm doing wrong.

这花了很长时间才弄清楚,因为症状并没有使问题变得明显!

This took so long to figure out as the symptom didn't make the problem obvious!

我是这样做的:

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

但是,我显然没有仔细考虑notifyItemMoved() 实际上在做什么.它只是通知适配器项目 i 已移至 indexOfCorrectItem 它并没有告诉适配器 indexOfCorrectItem 也已移至i.

But, I obviously didn't think through what notifyItemMoved() was actually doing. It is only notifying the adapter that item i has moved to indexOfCorrectItem it isn't telling the adapter that indexOfCorrectItem has also moved to i.

在幕后,它做了以下事情:

Under the covers it was doing the following:

  1. 将第 1 项移至第 3 项
  2. 移动 2 比 1 以填补空白
  3. 将原来的 3 移到 2 以填补空白
  4. notifyItemChanged(1);
  5. notifyItemChanged(3);

以上当然让第 3 项下移到第 2 项而没有刷新视图!是第 4 步和第 5 步通过使 item1 和 item3 正确显示而使 item2 不正确来隐藏问题!

The above of course leaves item 3 moved down to item 2 without a refreshed view! It was steps 4 and 5 which were hiding the problem by making item1 and item3 display correctly and leaving item2 incorrect!

当我意识到这一点时,我尝试了以下代码:

As soon as I realised this I tried the following code:

notifyItemMoved(indexOfCorrectItem, i);
notifyItemMoved(i, indexOfCorrectItem);

这使列表的顺序正确,但它使动画短路.

This left the list in the correct order, but it short circuited the animation.

所以,相反,我完全放弃了交换:

So, instead, I dumped swapping altogether:

mProductItems.remove(indexOfCorrectItem);
mProductItems.add(i, correctItem);
notifyItemMoved(indexOfCorrectItem, i);

这篇关于RecyclerView 使用 notifyItemMoved() 破坏视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 02:51