RecyclerView.ItemAnimator:删除项目时不会调用animateRemove

时间:2015-06-21 01:19:45

标签: android android-animation android-recyclerview

我正在开发一个应用程序并使用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

            }
        }

    }

}

0 个答案:

没有答案