问题描述
我在使用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移至3
- 将2处的位置移至1处以填补空白
- 将3到2的位置移动以填补空白
-
notifyItemChanged(1);
-
notifyItemChanged(3);
- Move item 1 to 3
- Move what was at 2 to 1 to fill the gap
- Move what was at 3 to 2 to fill the gap
notifyItemChanged(1);
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()破坏视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!