I am using RecyclerView
for the first time. Everything is working fine except that there is no animation on item removal even though the animation on item addit
Solved it.
The issue was that, after calling mAdapter.remove(position)
, another part of my code was calling mAdapter.notifyDataSetChanged()
which I assume stops the removal animation.
To sum up, if you call mAdapter.notifyDataSetChanged
while there is an animation ongoing the animation will stop.
Late but might be helpful to someone, who want {search items with animation}
Use below code In your activity or fragment where
yourAdapter.animateTo(filteredModelList);
Use below code in your RecyclerAdapter class
public void animateTo(List<CommonModel> models) {
applyAndAnimateRemovals(models);
applyAndAnimateAdditions(models);
applyAndAnimateMovedItems(models);
}
private void applyAndAnimateRemovals(List<CommonModel> newModels) {
for (int i = items.size() - 1; i >= 0; i--) {
final CommonModel model = items.get(i);
if (!newModels.contains(model)) {
removeItem(i);
}
}
}
private void applyAndAnimateAdditions(List<CommonModel> newModels) {
for (int i = 0, count = newModels.size(); i < count; i++) {
final CommonModel model = newModels.get(i);
if (!items.contains(model)) {
addItem(i, model);
}
}
}
private void applyAndAnimateMovedItems(List<CommonModel> newModels) {
for (int toPosition = newModels.size() - 1; toPosition >= 0; toPosition--) {
final CommonModel model = newModels.get(toPosition);
final int fromPosition = items.indexOf(model);
if (fromPosition >= 0 && fromPosition != toPosition) {
moveItem(fromPosition, toPosition);
}
}
}
private CommonModel removeItem(int position) {
final CommonModel model = items.remove(position);
notifyItemRemoved(position);
return model;
}
private void addItem(int position, CommonModel model) {
items.add(position, model);
notifyItemInserted(position);
}
private void moveItem(int fromPosition, int toPosition) {
final CommonModel model = items.remove(fromPosition);
items.add(toPosition, model);
notifyItemMoved(fromPosition, toPosition);
}
Use notifyItemRemoved(position)
instead of notifyDataSetChanged()
like below
myDataset.remove(position);
notifyItemRemoved(position);
because notifyDataSetChanged()
simply notifies the updated data without any animations.
after long debugging I realized I had to add setHasStableIds(true)
to my adapter and implement
@Override
public long getItemId(int position) {
return position;
}
after that remove animation began to work
I ran into same issue, and I fixed this by implementing my own RecyclerView, and in my recyclerview, I did this:
public class MyRecyclerView extends RecyclerView {
private View mEmptyView;
private AdapterDataObserver mDataObserver = new AdapterDataObserver() {
public void onChanged() {
super.onChanged();
updateEmptyView();
}
public void onItemRangeRemoved(int positionStart, int itemCount) {
super.onItemRangeRemoved(positionStart, itemCount);
updateEmptyView();
}
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
updateEmptyView();
}
};
// private void setAdapter() {}
private void updateEmptyView() {
// update empty view's visibility
}
}
Basically, when you add/remove item into/from recyclerview, you can call notifyItemInserted()/ notifyItemRemoved() and notifyItemRangeChanged(), these method will invoke onItemRangeRemoved()
/ onItemRangeInserted()
in mDataObserver
. So in these method, you can update empty view's visibility, and it will not break animations.
I was able to remove the view with the animation and updated indices as follows:
Within the adapter,
public boolean removeItem(int position) {
if (data.size() >= position + 1) {
data.remove(position);
return true;
}
return false;
}
While removing the views, call
if (adapter.removeItem(position)) {
adapter.notifyItemRemoved(position);
adapter.notifyItemRangeChanged(position, adapter.getItemCount());
}
I have used a boolean method to ensure that double clicks,etc. don't cause a crash.