我正在开发一个应用程序并使用custom ItemAnimator library。当我删除项目时,删除的项目不会动画。我认为库代码第一次没有正确工作,但我意识到即使我调用notifyItemRemoved方法也没有调用animateRemove()方法。
可能导致此问题的原因是什么?这是我的适配器类
package com.ayaroktay.bilkentmail.adapter;
import java.util.ArrayList;
import java.util.List;
import android.content.DialogInterface;
import android.graphics.Typeface;
import android.os.Handler;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.widget.RecyclerView;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import com.ayaroktay.bilkentmail.R;
import com.ayaroktay.bilkentmail.db.MailDatabaseManager;
import com.ayaroktay.bilkentmail.listener.OnUndoListener;
import com.ayaroktay.bilkentmail.manager.FolderManager;
import com.ayaroktay.bilkentmail.model.Mail;
import com.ayaroktay.bilkentmail.model.SyncTask;
import com.ayaroktay.bilkentmail.ui.SnackbarFactory;
import com.ayaroktay.bilkentmail.ui.ViewCreator;
import com.ayaroktay.bilkentmail.util.ContentFormatter;
import com.ayaroktay.bilkentmail.util.DateFormatter;
import com.github.brnunes.swipeablerecyclerview.SwipeableRecyclerViewTouchListener;
import tr.ayaroktay.widget.AsyncRecyclerView.Adapter;
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;
public MailListAdapter(List<Mail> dataset, AppCompatActivity activity) {
super(dataset);
this.activity = activity;
checkList = new SparseBooleanArray();
selectedItemCount = 0;
pendingActionList = new ArrayList<SyncTask>();
}
public class ViewHolder extends RecyclerView.ViewHolder implements
OnLongClickListener {
private View itemView;
ImageView avatar;
TextView subject;
TextView senderAndContent;
TextView date;
ImageView attachmentIcon;
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);
}
});
}
}
@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();
}
notifyDataSetChanged();
}
}
}
@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);
}
}
}
@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);
}
@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;
}
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.mail_action, menu);
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
checkList.clear();
selectedItemCount = 0;
notifyDataSetChanged();
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
mode.setTitle("" + selectedItemCount);
return true;
}
@Override
public boolean canSwipe(int position) {
boolean canSwipe;
canSwipe = (getItemViewType(position) != PROGRESS_ITEM_ID);
return canSwipe;
}
@Override
public void onDismissedBySwipeLeft(RecyclerView recyclerView,
int[] reverseSortedPositions) {
// dismisItems(recyclerView, reverseSortedPositions, MailAction.DELETE,
// true);
handleAction(SyncTask.DELETE, reverseSortedPositions);
}
@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;
mailAction = new SyncTask(action);
messageResId = -1;
switch (action) {
case SyncTask.DELETE:
for (int pos : positions) {
m = getItem(pos);
mailAction.addMail(m);
}
for (Mail mail : mailAction.getMails()) {
getDataset().remove(mail);
notifyItemRemoved(mail.getAdapterPosition());
}
e = Thread.currentThread().getStackTrace();
if (e[e.length - 2].getMethodName().equals("handleAction")) {
messageResId = R.string.action_delete_message;
} else {
messageResId = R.string.action_delete_swipe_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);
}
}
@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);
}
@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);
}
private class AvatarCloseAnimationListener implements AnimationListener {
ViewHolder vh;
public AvatarCloseAnimationListener(ViewHolder vh) {
this.vh = vh;
}
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
int imageRes;
Animation anim;
if (!checkList.get(vh.getAdapterPosition())) {
imageRes = R.drawable.ic_check;
vh.itemView.setSelected(true);
} else {
imageRes = R.drawable.ic_avatar;
vh.itemView.setSelected(false);
}
anim = AnimationUtils.loadAnimation(vh.itemView.getContext(),
R.anim.from_middle);
anim.setAnimationListener(new AvatarOpenAnimationListener(vh));
vh.avatar.setImageResource(imageRes);
vh.avatar.startAnimation(anim);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
}
private class AvatarOpenAnimationListener implements AnimationListener {
ViewHolder vh;
public AvatarOpenAnimationListener(ViewHolder vh) {
this.vh = vh;
}
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
vh.performChecking(true);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
}
private class SnackbarMessageEndedListener implements Runnable {
SyncTask task;
public SnackbarMessageEndedListener(SyncTask task) {
this.task = task;
}
@Override
public void run() {
MailDatabaseManager dbManager;
if (pendingActionList.indexOf(task) > -1) {
pendingActionList.remove(task);
dbManager = new MailDatabaseManager(activity);
switch (task.getAction()) {
case SyncTask.DELETE:
for (Mail m : task.getMails()) {
dbManager.deleteMail(m.getId());
}
break;
case SyncTask.MARK_READ:
for (Mail m : task.getMails()) {
dbManager.updateSeenStatus(m.getId(), true);
}
break;
case SyncTask.MARK_UNREAD:
for (Mail m : task.getMails()) {
dbManager.updateSeenStatus(m.getId(), false);
}
break;
case SyncTask.MOVE:
for (Mail m : task.getMails()) {
dbManager.updateFolder(m.getId(), (String) task
.getActionData(SyncTask.KEY_FOLDER));
}
break;
}
// TODO pass task object to sync service
}
}
}
}