我有关于ItemAnimator的问题。当我想从recyclerview删除项目删除动画无法正常工作。它可以在下面的gif中看起来(动画放慢了速度)
http://i.hizliresim.com/vEW3yp.gif
我使用了DefaultItemAnimator(由Google提供)和两个不同的库。但结果仍然相同。问题出在适配器类中,但我仍然无法找到问题所在。这是我的代码
从列表中删除项目的部分代码
for (int pos : positions) {
m = getItem(pos);
mailAction.addMail(m);
getDataset().remove(m);
notifyItemRemoved(pos);
}
这是整个适配器类的代码(不包括内部类)
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());
}
}
}
答案 0 :(得分:1)
确保最后添加itemAnimator。在添加适配器之前添加它时遇到了同样的问题。片段:
MixingSampleProvider
答案 1 :(得分:0)
我觉得你有动画同步问题。如果您使用自己的隐藏动画扩展SimpleItemAnimator
并覆盖onRemoveStarting
metod,则可以解决此问题。