2015-06-22 58 views
0

我有一個關於ItemAnimator的問題。當我想從recyclerview中刪除一個項目時,刪除動畫無法正常工作。它可以在下面的gif來似乎(動畫減慢)RecyclerView ItemAnimator無法正常工作

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

我用DefaultItemAnimator(由谷歌提供)和兩種不同的庫。但結果仍然相同。問題在適配器類中,但我仍然無法找出問題所在。這裏是我的代碼

部分的代碼,從列表中刪除的項

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

它在我看來像你有動畫同步問題。如果您擴展SimpleItemAnimator並用您自己的隱藏動畫覆蓋onRemoveStarting metod,則可以解決此問題。

0

確保您最後添加itemAnimator。在添加適配器之前添加它時遇到同樣的問題。摘錄此處:

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); 
相關問題