2

I have an issue about ItemAnimator. When I want to remove an item from recyclerview removal animation does not work properly. It can be seem in gif below (Animation was slowed down)

http://i.hizliresim.com/vEW3yp.gif

I used DefaultItemAnimator (provided by Google) and two different library. However result is still same. Problem is in adapter class, but I still couldn't find out the problem. Here is my code

Part of code that removes an item from the list

for (int pos : positions) { m = getItem(pos); mailAction.addMail(m); getDataset().remove(m); notifyItemRemoved(pos); } 

This is code of whole adapter class (Inner classes not included)

public class MailListAdapter extends Adapter<Mail, MailListAdapter.ViewHolder> implements ActionMode.Callback, SwipeableRecyclerViewTouchListener.SwipeListener, OnUndoListener, DialogInterface.OnClickListener { private final int SNACKBAR_TIME = 4000; private ArrayList<SyncTask> pendingActionList; private SparseBooleanArray checkList; private AppCompatActivity activity; private ActionMode actionMode; private int selectedItemCount; /** * @param dataset */ public MailListAdapter(List<Mail> dataset, AppCompatActivity activity) { super(dataset); this.activity = activity; checkList = new SparseBooleanArray(); selectedItemCount = 0; pendingActionList = new ArrayList<SyncTask>(); } /* * (non-Javadoc) * * @see * android.support.v7.widget.RecyclerView.Adapter#onCreateViewHolder(android * .view.ViewGroup, int) */ @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v; if (viewType == PROGRESS_ITEM_ID) { v = getProgressItemView(); } else { v = LayoutInflater.from(parent.getContext()).inflate( R.layout.item_mail, null); } return new ViewHolder(v); } /* * (non-Javadoc) * * @see * android.support.v7.widget.RecyclerView.Adapter#onBindViewHolder(android * .support.v7.widget.RecyclerView.ViewHolder, int) */ @Override public void onBindViewHolder(ViewHolder vh, int position) { Mail m; int visibility; if (position < getDataset().size()) { m = getItem(position); m.setAdapterPosition(position); visibility = m.hasAttachment() ? View.VISIBLE : View.GONE; vh.subject.setText(m.getSubject()); vh.senderAndContent.setText(ContentFormatter.format(m)); vh.date.setText(DateFormatter.format(m.getDate())); vh.attachmentIcon.setVisibility(visibility); if (!m.isSeen()) { vh.subject.setTypeface(null, Typeface.BOLD); } else { vh.subject.setTypeface(null, Typeface.NORMAL); } if (checkList.get(position)) { vh.itemView.setSelected(true); vh.avatar.setImageResource(R.drawable.ic_check); } else { vh.itemView.setSelected(false); vh.avatar.setImageResource(R.drawable.ic_avatar); } } } /* * (non-Javadoc) * * @see * android.support.v7.view.ActionMode.Callback#onActionItemClicked(android * .support.v7.view.ActionMode, android.view.MenuItem) */ @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { int id, action; action = -1; id = item.getItemId(); if (id == R.id.action_delete) { action = SyncTask.DELETE; } else if (id == R.id.action_mark_read) { action = SyncTask.MARK_READ; } else if (id == R.id.action_mark_unread) { action = SyncTask.MARK_UNREAD; } else if (id == R.id.action_move) { action = SyncTask.MOVE; } if (action < 0) { return false; } else { handleAction(action); mode.finish(); return true; } } /* * (non-Javadoc) * * @see * android.support.v7.view.ActionMode.Callback#onCreateActionMode(android * .support.v7.view.ActionMode, android.view.Menu) */ @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { mode.getMenuInflater().inflate(R.menu.mail_action, menu); return true; } /* * (non-Javadoc) * * @see * android.support.v7.view.ActionMode.Callback#onDestroyActionMode(android * .support.v7.view.ActionMode) */ @Override public void onDestroyActionMode(ActionMode mode) { checkList.clear(); selectedItemCount = 0; // notifyDataSetChanged(); } /* * (non-Javadoc) * * @see * android.support.v7.view.ActionMode.Callback#onPrepareActionMode(android * .support.v7.view.ActionMode, android.view.Menu) */ @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { mode.setTitle("" + selectedItemCount); return true; } /* * (non-Javadoc) * * @see * com.ayaroktay.bilkentmail.listener.SwipeableRecyclerViewTouchListener * .SwipeListener#canSwipe(int) */ @Override public boolean canSwipe(int position) { boolean canSwipe; canSwipe = (getItemViewType(position) != PROGRESS_ITEM_ID); return canSwipe; } /* * (non-Javadoc) * * @see * com.ayaroktay.bilkentmail.listener.SwipeableRecyclerViewTouchListener * .SwipeListener * #onDismissedBySwipeLeft(android.support.v7.widget.RecyclerView, int[]) */ @Override public void onDismissedBySwipeLeft(RecyclerView recyclerView, int[] reverseSortedPositions) { // dismisItems(recyclerView, reverseSortedPositions, MailAction.DELETE, // true); handleAction(SyncTask.DELETE, reverseSortedPositions); } /* * (non-Javadoc) * * @see * com.ayaroktay.bilkentmail.listener.SwipeableRecyclerViewTouchListener * .SwipeListener * #onDismissedBySwipeRight(android.support.v7.widget.RecyclerView, int[]) */ @Override public void onDismissedBySwipeRight(RecyclerView recyclerView, int[] reverseSortedPositions) { // dismisItems(recyclerView, reverseSortedPositions, MailAction.DELETE, // true); handleAction(SyncTask.DELETE, reverseSortedPositions); } private void handleAction(int action) { int[] positions; int index, position, j; positions = new int[selectedItemCount]; j = 0; while ((index = checkList.indexOfValue(true)) > -1) { position = checkList.keyAt(index); positions[j] = position; checkList.delete(position); j++; } handleAction(action, positions); } private void handleAction(int action, int[] positions) { SyncTask mailAction; Mail m; int messageResId; StackTraceElement[] e; FolderManager fm; boolean isSwipe; mailAction = new SyncTask(action); messageResId = -1; e = Thread.currentThread().getStackTrace(); switch (action) { case SyncTask.DELETE: isSwipe = false; for (int i = 0; i < e.length; i++) { if (e[i].getClassName().equals(MailListAdapter.class.getName())) { isSwipe = e[i].getMethodName().startsWith( "onDismissedBySwipe"); if (isSwipe) { i = e.length; } } } for (int pos : positions) { m = getItem(pos); mailAction.addMail(m); getDataset().remove(m); if (!isSwipe) { notifyItemRemoved(pos); } else { notifyDataSetChanged(); } } for (Mail mail : mailAction.getMails()) { } if (isSwipe) { messageResId = R.string.action_delete_swipe_message; } else { messageResId = R.string.action_delete_message; } break; case SyncTask.MARK_READ: mailAction.addActionData(SyncTask.KEY_SEEN, true); for (int pos : positions) { m = getItem(pos); m.setSeen(true); mailAction.addMail(m); notifyItemChanged(pos); } messageResId = R.string.action_mark_read_message; break; case SyncTask.MARK_UNREAD: mailAction.addActionData(SyncTask.KEY_SEEN, false); for (int pos : positions) { m = getItem(pos); m.setSeen(false); mailAction.addMail(m); notifyItemChanged(pos); } messageResId = R.string.action_mark_unread_message; break; case SyncTask.MOVE: for (int pos : positions) { m = getItem(pos); mailAction.addMail(m); } fm = new FolderManager(activity); ViewCreator.getInstance(activity) .createChangeFolderDialog(this, fm.getFolderNameArray()) .show(); break; default: return; } pendingActionList.add(mailAction); if (messageResId != -1) { showMessage(messageResId); // new Handler().postDelayed(new SnackbarMessageEndedListener( // mailAction), SNACKBAR_TIME); } } /* * (non-Javadoc) * * @see * android.content.DialogInterface.OnClickListener#onClick(android.content * .DialogInterface, int) */ @Override public void onClick(DialogInterface dialog, int which) { FolderManager fm; String folderName; SyncTask mAction; fm = new FolderManager(activity); folderName = fm.getFolderNameArray()[which]; mAction = pendingActionList.get(pendingActionList.size() - 1); mAction.addActionData(SyncTask.KEY_FOLDER, folderName); for (Mail m : mAction.getMails()) { getDataset().remove(m); notifyItemRemoved(m.getAdapterPosition()); } showMessage(R.string.action_move_message); new Handler().postDelayed(new SnackbarMessageEndedListener(mAction), SNACKBAR_TIME); } /* * (non-Javadoc) * * @see com.ayaroktay.bilkentmail.listener.OnUndoListener#onUndo() */ @Override public void onUndo() { SyncTask mAction; mAction = pendingActionList.remove(0); undoChanges(mAction); } private void undoChanges(SyncTask pendingAction) { switch (pendingAction.getAction()) { case SyncTask.DELETE: for (Mail m : pendingAction.getMails()) { add(m.getAdapterPosition(), m); notifyItemInserted(m.getAdapterPosition()); } break; case SyncTask.MARK_READ: for (Mail m : pendingAction.getMails()) { m.setSeen(false); notifyItemChanged(m.getAdapterPosition()); } break; case SyncTask.MARK_UNREAD: for (Mail m : pendingAction.getMails()) { m.setSeen(true); notifyItemChanged(m.getAdapterPosition()); } break; case SyncTask.MOVE: for (Mail m : pendingAction.getMails()) { add(m.getAdapterPosition(), m); notifyItemInserted(m.getAdapterPosition()); } break; default: return; } } private void showMessage(int messageResId) { CoordinatorLayout cLayout; cLayout = (CoordinatorLayout) getObserver().getParent().getParent(); SnackbarFactory.showWithUndo(cLayout, messageResId, this); } public class ViewHolder extends RecyclerView.ViewHolder implements OnLongClickListener { private View itemView; ImageView avatar; TextView subject; TextView senderAndContent; TextView date; ImageView attachmentIcon; /** * Constructs new * {@link com.ayaroktay.bilkentmail.adapter.MailListAdapter.ViewHolder * View Holder} with given view object * * @param itemView * Item view */ public ViewHolder(View itemView) { super(itemView); int tag; tag = itemView.getTag() == null ? 0 : (Integer) itemView.getTag(); if (tag != PROGRESS_ITEM_ID) { this.itemView = itemView; avatar = (ImageView) itemView.findViewById(R.id.iv_avatar); attachmentIcon = (ImageView) itemView .findViewById(R.id.ic_attachment); subject = (TextView) itemView.findViewById(R.id.tv_subject); senderAndContent = (TextView) itemView .findViewById(R.id.tv_sender_and_content); date = (TextView) itemView.findViewById(R.id.tv_receive_date); // Set long click listener itemView.setOnLongClickListener(this); // Set click listener for avatar avatar.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { Animation anim; // Set animation anim = AnimationUtils.loadAnimation(v.getContext(), R.anim.to_middle); // Set animation listener anim.setAnimationListener(new AvatarCloseAnimationListener( ViewHolder.this)); // Start animation avatar.startAnimation(anim); } }); } } /* * (non-Javadoc) * * @see * android.view.View.OnLongClickListener#onLongClick(android.view.View) */ @Override public boolean onLongClick(View v) { performChecking(false); return true; } public void performChecking(boolean isCalledFromAvatar) { if (!isCalledFromAvatar) { avatar.performClick(); } else { boolean currentStatus; currentStatus = !checkList.get(getAdapterPosition()); checkList.put(getAdapterPosition(), currentStatus); if (selectedItemCount == 0 && currentStatus) { actionMode = activity .startSupportActionMode(MailListAdapter.this); } selectedItemCount = currentStatus ? selectedItemCount + 1 : selectedItemCount - 1; if (selectedItemCount == 0) { actionMode.finish(); } else { actionMode.invalidate(); } notifyItemChanged(getAdapterPosition()); } } } 

2 Answers 2

3

Make sure that you add the itemAnimator last. I had the same issue when adding it before adding the Adapter. Snippet here:

 LinearLayoutManager layoutManager = new LinearLayoutManager(this); layoutManager.setOrientation(LinearLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(layoutManager); mAdapter = new AppsAdapter(this); mRecyclerView.setAdapter(mAdapter); RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator(); itemAnimator.setAddDuration(1000); itemAnimator.setRemoveDuration(1000); mRecyclerView.setItemAnimator(itemAnimator); 
Sign up to request clarification or add additional context in comments.

Comments

0

It looks to me like you have animation synchronization problem. You may workaround that if you extend SimpleItemAnimator and override onRemoveStarting metod with your own hide animation.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.