I am building a component based on RecyclerView, allowing user to reorder items by drag and drop. Once I am on the DragListener side, I need the position it has in the adapter in order to perform correct move, but I only have access to the view. So here is what I am doing in the adapter view binding :
@Override public void onBindViewHolder(ViewHolder viewHolder, int position) { Track track = mArray.get(position); viewHolder.itemView.setTag(R.string.TAG_ITEM_POSITION, position); }
Does it seem correct to you ? Because if I move an item like this :
public void move(int from, int to){ Track track = mArray.remove(from); mArray.add(to, track); notifyItemMoved(from, to); }
then position tag is not correct anymore, and if I notifyDataSetChanged(), I lose the fancy animation. Any suggestion ?
notifyDataSetChanged. Notify any registered observers that the data set has changed. There are two different classes of data change events, item changes and structural changes.
setHasFixedSize(true) means the RecyclerView has children (items) that has fixed width and height. This allows the RecyclerView to optimize better by figuring out the exact height and width of the entire list based on the your adapter.
Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
onCreateViewHolder(parent: ViewGroup, viewType: Int) In onCreateViewHolder, we will inflate the view that we will be using to hold each list item. This method will be called when RecyclerView needs a new ViewHolder of the given type to represent. The params are the Viewgroup parent and int viewType.
There is a way to preserve fancy animations with just notifyDataSetChanged()
You need to make your own GridLayoutManager
with overriden supportsPredictiveItemAnimations()
method returning true
;
You need to mAdapter.setHasStableIds(true)
The part I find tricky is you need to override you adapter's getItemId()
method. It should return value that is truly unique and not a direct function of position
. Something like mItems.get(position).hashCode()
Worked perfectly fine in my case - beautiful animations for adding, removing and moving items only using notifyDataSetChanged()
No, it is wrong. First of all, you cannot reference to the position passed to the onBindViewHolder after that method returns. RecyclerView will not rebind a view when its position changes (due to items moving etc).
Instead, you can use ViewHolder#getPosition()
which will return you the updated position.
If you fix that, your move code should work & provide nice animations.
Calling notifyDataSetChanged
will prevent predictive animations so avoid it as long as you can. See documentation for details.
Edit (from comment): to get position from the outside, get child view holder from recyclerview and then get position from the vh. See RecyclerView api for details
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With