RecyclerView ItemAnimator无法正常工作

时间:2015-06-22 10:16:00

标签: android animation android-recyclerview

我有关于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());
            }
        }
    }

2 个答案:

答案 0 :(得分:1)

确保最后添加itemAnimator。在添加适配器之前添加它时遇到了同样的问题。片段:

MixingSampleProvider

答案 1 :(得分:0)

我觉得你有动画同步问题。如果您使用自己的隐藏动画扩展SimpleItemAnimator并覆盖onRemoveStarting metod,则可以解决此问题。

相关问题