Skip to content Skip to sidebar Skip to footer

Recyclerview Corrupts View Using Notifyitemmoved()

I'm having a problem with using the notifyItemMoved() method. It seems to be incorrectly displaying unmoved views. My list has 4 element in it. What I want to do is animate a swap

Solution 1:

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!

I was doing this:

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

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

Under the covers it was doing the following:

  1. Move item 1 to 3
  2. Move what was at 2 to 1 to fill the gap
  3. Move what was at 3 to 2 to fill the gap
  4. notifyItemChanged(1);
  5. notifyItemChanged(3);

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);

Solution 2:

I had the same issue. RecyclerView-Items are corrupt on drag&drop. But I have found a simple solution: In your RecyclerView.Adapter.class be sure to have the following

@OverridepubliclonggetItemId(int position) {
    // here code for getting the right itemID, // i.e. return super.getItemId(mPosition);// where mPosition ist the Position in the Collection.
}

You must return the right itemID for the position. From now on the Items are not corrupt.

Solution 3:

I had the same issue and I actually handled it differently too, with my way, the animation will stay the same and you won't have any trouble of items at wrong positions anymore :

@Override
publicvoidonRowMoved(int fromPosition, int toPosition){
    if (fromPosition < toPosition) {
        for (int i = fromPosition; i < toPosition; i++) {
            Collections.swap(listOfItem, i, i + 1);
        }
    } else {
        for (int i = fromPosition; i > toPosition; i--) {
            Collections.swap(listOfItem, i, i - 1);
        }
    }
    notifyItemMoved(fromPosition, toPosition);
}

With this, you can reorder items without any issues

Tutorial used to fix my issue

Solution 4:

To get the actual position of your item after a drag&drop, add this method to your adapter:

privateintgetItemPosition(Item item){ // (<-- replace with your item)int i = 0;
    // (replace with your items and methods here)for (Item currentItem : mItems) {
        if (currentItem.getItemId() == item.getItemId()) break;
        i++;
    }
    return i;
}

and call this instead of the position given by the viewHolder.

Solution 5:

Well, I handled it in a slightly different way, might help others.

        Collections.swap(mItemList, fromPosition, toPosition);
        // Need to do below, because NotifyItemMove only handle one sided move
        Item fromItem = mItemList.get(fromPosition);
        Item toItem = mItemList.get(toPosition);
        notifyItemChanged(fromPosition, toItem);
        notifyItemChanged(toPosition, fromItem);

I had to reorder items on a grid, and save the positions to a file. @Graeme was right, but i didn't wanted to give up on swapping. So just like @saganaut i sticked to notifyItemChanged. But only using notifyItemChanged sometimes left both swapped items on my grid with same items, so I binded the items with notifyItemChanged. It is not killing the animation, and is working as expected.

Post a Comment for "Recyclerview Corrupts View Using Notifyitemmoved()"