RecyclerView<第十六篇>:條目動畫之自定義DefaultItemAnimator

爲了讓RecyclerView更加用戶友好,可以給條目添加動畫,RecyclerView可以設置條目動畫

設置條目動畫的代碼是:

mRecyclerView.setItemAnimator(new DefaultItemAnimator());

可以給RecyclerView設置一個默認的動畫,使用默認動畫的話可以給條目設置動畫時間

    DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator();
    defaultItemAnimator.setRemoveDuration(200);
    defaultItemAnimator.setAddDuration(200);
    defaultItemAnimator.setMoveDuration(200);
    defaultItemAnimator.setChangeDuration(200);
    mRecyclerView.setItemAnimator(defaultItemAnimator);

另外,還可以自定義一個動畫,這樣就需要深入研究DefaultItemAnimator類了。

DefaultItemAnimator的最終父類是ItemAnimator,該類是RecyclerView的內部抽象類,根據它抽象的特性,我們可以自定義ItemAnimator,當然,如果這樣的話就比較複雜了,因此,就自定義DefaultItemAnimator了。

public class MyCustomItemAnimator extends DefaultItemAnimator {

    @Override
    public boolean animateRemove(RecyclerView.ViewHolder holder) {
        //刪除條目動畫實現
        return super.animateRemove(holder);
    }

    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        //添加條目動畫實現
        return super.animateAdd(holder);
    }

    @Override
    public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
        //移動條目動畫實現
        return super.animateMove(holder, fromX, fromY, toX, toY);
    }

    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
        //改變條目動畫實現
        return super.animateChange(oldHolder, newHolder, fromX, fromY, toX, toY);
    }
}

如上代碼,動畫的實現主要體現在animateRemoveanimateAddanimateMoveanimateChange這四個方法。

在不做修改的情況下,條目動畫都是默認的,想要學會自定義動畫,那麼首先需要研究下DefaultItemAnimator類的源碼。

研究源碼後發現,當觸發添加條目動作時會執行

public boolean animateAdd(ViewHolder holder) {
    this.resetAnimation(holder);
    holder.itemView.setAlpha(0.0F);
    this.mPendingAdditions.add(holder);
    return true;
}

當觸發條目移動動作時執行

public boolean animateMove(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
    View view = holder.itemView;
    fromX += (int)holder.itemView.getTranslationX();
    fromY += (int)holder.itemView.getTranslationY();
    this.resetAnimation(holder);
    int deltaX = toX - fromX;
    int deltaY = toY - fromY;
    if (deltaX == 0 && deltaY == 0) {
        this.dispatchMoveFinished(holder);
        return false;
    } else {
        if (deltaX != 0) {
            view.setTranslationX((float)(-deltaX));
        }

        if (deltaY != 0) {
            view.setTranslationY((float)(-deltaY));
        }

        this.mPendingMoves.add(new DefaultItemAnimator.MoveInfo(holder, fromX, fromY, toX, toY));
        return true;
    }
}

當觸發條目刪除時執行

public boolean animateRemove(ViewHolder holder) {
    this.resetAnimation(holder);
    this.mPendingRemovals.add(holder);
    return true;
}

當條目狀態改變時

public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
    if (oldHolder == newHolder) {
        return this.animateMove(oldHolder, fromX, fromY, toX, toY);
    } else {
        float prevTranslationX = oldHolder.itemView.getTranslationX();
        float prevTranslationY = oldHolder.itemView.getTranslationY();
        float prevAlpha = oldHolder.itemView.getAlpha();
        this.resetAnimation(oldHolder);
        int deltaX = (int)((float)(toX - fromX) - prevTranslationX);
        int deltaY = (int)((float)(toY - fromY) - prevTranslationY);
        oldHolder.itemView.setTranslationX(prevTranslationX);
        oldHolder.itemView.setTranslationY(prevTranslationY);
        oldHolder.itemView.setAlpha(prevAlpha);
        if (newHolder != null) {
            this.resetAnimation(newHolder);
            newHolder.itemView.setTranslationX((float)(-deltaX));
            newHolder.itemView.setTranslationY((float)(-deltaY));
            newHolder.itemView.setAlpha(0.0F);
        }

        this.mPendingChanges.add(new DefaultItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
        return true;
    }
}

以上四個方法並不是爲了執行動畫,而是初始化動畫的準備工作,它們的作用大致有兩個:
【一】 設置ViewHolder的初始狀態,比如:

newHolder.itemView.setAlpha(0.0F);

【二】 存儲將要執行動畫的ViewHolder,比如:

//存儲將要執行動畫的ViewHolder(移除Item)
this.mPendingRemovals.add(holder);

//存儲將要執行動畫的ViewHolder(Item狀態改變)
this.mPendingChanges.add(new DefaultItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));

//存儲將要執行動畫的ViewHolder(位移Item)
this.mPendingMoves.add(new DefaultItemAnimator.MoveInfo(holder, fromX, fromY, toX, toY));

//存儲將要執行動畫的ViewHolder(新增Item)
this.mPendingAdditions.add(holder);

當一切準備工作做好之後,開始執行runPendingAnimations方法

public void runPendingAnimations() {
    boolean removalsPending = !this.mPendingRemovals.isEmpty();
    boolean movesPending = !this.mPendingMoves.isEmpty();
    boolean changesPending = !this.mPendingChanges.isEmpty();
    boolean additionsPending = !this.mPendingAdditions.isEmpty();
    if (removalsPending || movesPending || additionsPending || changesPending) {
        Iterator var5 = this.mPendingRemovals.iterator();

        while(var5.hasNext()) {
            ViewHolder holder = (ViewHolder)var5.next();
            this.animateRemoveImpl(holder);
        }

        this.mPendingRemovals.clear();
        final ArrayList additions;
        Runnable adder;
        if (movesPending) {
            additions = new ArrayList();
            additions.addAll(this.mPendingMoves);
            this.mMovesList.add(additions);
            this.mPendingMoves.clear();
            adder = new Runnable() {
                public void run() {
                    Iterator var1 = additions.iterator();

                    while(var1.hasNext()) {
                        DefaultItemAnimator.MoveInfo moveInfo = (DefaultItemAnimator.MoveInfo)var1.next();
                        DefaultItemAnimator.this.animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, moveInfo.toY);
                    }

                    additions.clear();
                    DefaultItemAnimator.this.mMovesList.remove(additions);
                }
            };
            if (removalsPending) {
                View view = ((DefaultItemAnimator.MoveInfo)additions.get(0)).holder.itemView;
                ViewCompat.postOnAnimationDelayed(view, adder, this.getRemoveDuration());
            } else {
                adder.run();
            }
        }

        if (changesPending) {
            additions = new ArrayList();
            additions.addAll(this.mPendingChanges);
            this.mChangesList.add(additions);
            this.mPendingChanges.clear();
            adder = new Runnable() {
                public void run() {
                    Iterator var1 = additions.iterator();

                    while(var1.hasNext()) {
                        DefaultItemAnimator.ChangeInfo change = (DefaultItemAnimator.ChangeInfo)var1.next();
                        DefaultItemAnimator.this.animateChangeImpl(change);
                    }

                    additions.clear();
                    DefaultItemAnimator.this.mChangesList.remove(additions);
                }
            };
            if (removalsPending) {
                ViewHolder holder = ((DefaultItemAnimator.ChangeInfo)additions.get(0)).oldHolder;
                ViewCompat.postOnAnimationDelayed(holder.itemView, adder, this.getRemoveDuration());
            } else {
                adder.run();
            }
        }

        if (additionsPending) {
            additions = new ArrayList();
            additions.addAll(this.mPendingAdditions);
            this.mAdditionsList.add(additions);
            this.mPendingAdditions.clear();
            adder = new Runnable() {
                public void run() {
                    Iterator var1 = additions.iterator();

                    while(var1.hasNext()) {
                        ViewHolder holder = (ViewHolder)var1.next();
                        DefaultItemAnimator.this.animateAddImpl(holder);
                    }

                    additions.clear();
                    DefaultItemAnimator.this.mAdditionsList.remove(additions);
                }
            };
            if (!removalsPending && !movesPending && !changesPending) {
                adder.run();
            } else {
                long removeDuration = removalsPending ? this.getRemoveDuration() : 0L;
                long moveDuration = movesPending ? this.getMoveDuration() : 0L;
                long changeDuration = changesPending ? this.getChangeDuration() : 0L;
                long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
                View view = ((ViewHolder)additions.get(0)).itemView;
                ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
            }
        }

    }
}

runPendingAnimations方法中,有執行四種動畫的方法,分別是:

【animateRemoveImpl】 刪除動畫
【animateChangeImpl】 狀態改變動畫
【animateAddImpl】 添加條目動畫
【animateMoveImpl】 條目位移動畫

所以,可以斷定,runPendingAnimations方法的作用是執行所有集合中的動畫。

RecyclerView條目動畫執行流程

從源碼分析,RecyclerView條目動畫執行過程是:(很重要)

animateAdd-->runPendingAnimations-->animateAddImpl
animateMove-->runPendingAnimations-->animateMoveImpl
animateRemove-->runPendingAnimations-->animateRemoveImpl
animateChange-->runPendingAnimations-->animateChangeImpl

前面源碼看不懂不要緊,但是條目動畫基本執行流程必須要清楚,因爲接下來開始一步一步的手寫自定義DefaultItemAnimator。

【第一步】 新建DefaultItemAnimator類,繼承DefaultItemAnimator

我們看一下DefaultItemAnimator類,它的回調方法都是從父類DefaultItemAnimator重寫過來的

public class MyCustomItemAnimator extends DefaultItemAnimator {

    @Override
    public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull List<Object> payloads) {
        return super.canReuseUpdatedViewHolder(viewHolder, payloads);
    }

    @Override
    public void runPendingAnimations() {
        super.runPendingAnimations();
    }

    @Override
    public boolean animateRemove(RecyclerView.ViewHolder holder) {
        return super.animateRemove(holder);
    }

    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        return super.animateAdd(holder);
    }

    @Override
    public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
        return super.animateMove(holder, fromX, fromY, toX, toY);
    }

    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
        return super.animateChange(oldHolder, newHolder, fromX, fromY, toX, toY);
    }

    @Override
    public void endAnimation(RecyclerView.ViewHolder item) {
        super.endAnimation(item);
    }

    @Override
    public boolean isRunning() {
        return super.isRunning();
    }

    @Override
    public void endAnimations() {
        super.endAnimations();
    }
    
}

那些方法有什麼用呢?(重點)

  • canReuseUpdatedViewHolder

RecyclerView的複用機制是否可用,這裏一般默認即可,或者將這個返回值改成true,也就是說,默認複用機制可用。然而,決定RecyclerView是否可以複用不僅僅是根據canReuseUpdatedViewHolder方法的返回值,而且還需要看Adapter中的getItemViewType方法的返回值。

也就是說,當canReuseUpdatedViewHolder的返回值爲true並且多個ViewHolder爲同一個類型,說明可複用。

@Override
public int getItemViewType(int position) {
    //所有ViewHolder類型都是0,所有都可複用
    return 0;
}

@Override
public int getItemViewType(int position) {
    //所有ViewHolder類型都是不一樣,所有都不可複用
    return position;
}

@Override
public int getItemViewType(int position) {
    //ViewHolder類型爲0的可以相互複用,ViewHolder類型爲1的可以相互複用,不同類型的不可相互複用
    if(a){
        return 0;
    }else{
        return 1;
    }
}
  • animateAdd

這個方法的作用是存儲即將被添加的ViewHolder。
這個方法的執行是最爲頻繁的了。
當RecyclerView刪除某一項時,刪除項之後的項都要被重新添加;
當RecyclerView新增某項時,新增項之後的項都要被重新添加;
當RecyclerView指定兩個項相互對換位移時,這兩項需要被重新添加;

  • animateRemove

這個方法的作用是存儲即將被刪除的ViewHolder。
當刪除某項時,會執行這個方法。

  • animateMove

這個方法的作用是存儲即將被位移的ViewHolder。
當新增項、刪除項、項狀態改變時都會執行到這個回調。
需要說明的是,當交換某兩項位置時,這裏只會觸發animateAdd方法,而不會執行animateMove方法。

  • animateChange

這個方法的作用是存儲即將狀態被改變的ViewHolder。
當項狀態改變時,執行animateChange方法。

  • isRunning

判斷當前動畫是否正在執行。

  • runPendingAnimations

這個方法纔是最終執行動畫的地方,animateAdd、animateRemove、animateMove、animateChange這四個方法只是將將要執行動畫的ViewHolder保存到集合裏面,最終這四個集合會在runPendingAnimations方法裏遍歷,將所有的ViewHolder執行動畫。

  • endAnimation

結束動畫時調用。

  • endAnimations

結束動畫時調用。

【第二步】 條目被添加、刪除、位移、改變時會執行到哪些方法?

  • 添加項
adapter.notifyItemInserted(position);

當在指定位置插入某項時,會執行animateMove和animateAdd方法存儲ViewHolder,最後執行runPendingAnimations方法執行動畫。

  • 刪除項
adapter.notifyItemRemoved(position);

當刪除某項時,會執行animateRemove、animateAdd、animateMove這三個方法存儲ViewHolder,最後執行runPendingAnimations方法執行動畫。

  • 位移項
adapter.notifyItemMoved(position, position + 1);

當兩個項互相交換位置時,執行animateAdd方法存儲ViewHolder,最後執行runPendingAnimations方法執行動畫。

  • 項狀態改變
adapter.notifyItemChanged(position);

當項狀態改變時,執行animateChange和animateMove方法存儲ViewHolder,最後執行runPendingAnimations方法執行動畫。

【第三步】 將DefaultItemAnimator類中的基本實現拷貝到MyCustomItemAnimator方法中,報錯的地方可以自行修改。

以下貼出我整理之後的代碼

public class MyCustomItemAnimator extends DefaultItemAnimator {

    //用於存儲將要移動的MoveInfo對象
    private ArrayList<MyCustomItemAnimator.MoveInfo> mPendingMoves = new ArrayList();
    //MoveInfo的臨時存儲集合
    private ArrayList<ArrayList<MyCustomItemAnimator.MoveInfo>> mMovesList = new ArrayList();
    //用於存儲正在執行移動動畫的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mMoveAnimations = new ArrayList();
    //用於存儲將要被添加的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList();
    //存儲被添加的ViewHolder的臨時集合
    private ArrayList<ArrayList<RecyclerView.ViewHolder>> mAdditionsList = new ArrayList();
    //用於存儲正在執行添加動畫的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mAddAnimations = new ArrayList();
    //用於存儲將要刪除的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mPendingRemovals = new ArrayList();
    //用於存儲正在執行刪除動畫的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mRemoveAnimations = new ArrayList();
    //用於存儲將要改變的ViewHolder
    private ArrayList<MyCustomItemAnimator.ChangeInfo> mPendingChanges = new ArrayList();
    //存儲被改變的ViewHolder的臨時集合
    private ArrayList<ArrayList<MyCustomItemAnimator.ChangeInfo>> mChangesList = new ArrayList();
    //用於存儲正在執行改變動畫的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mChangeAnimations = new ArrayList();

    //定義一個插值器:先向相反方向改變,再加速播放,會超出目標值
    private AnticipateOvershootInterpolator accelerateDecelerateInterpolator;

    @Override
    public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
        return true;
    }


    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        //添加條目動畫實現

        //開始重置動畫
        holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
        endAnimation(holder);

        //讓被添加的條目初始完全透明
        holder.itemView.setAlpha(0.0f);

        //把即將被添加的ViewHolder暫時緩存到mPendingAdditions中
        mPendingAdditions.add(holder);
        return true;
    }


    @Override
    public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
        //移動條目動畫實現

        View view = holder.itemView;
        fromX += (int)holder.itemView.getTranslationX();
        fromY += (int)holder.itemView.getTranslationY();

        //開始重置動畫
        holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
        endAnimation(holder);

        int deltaX = toX - fromX;
        int deltaY = toY - fromY;
        if (deltaX == 0 && deltaY == 0) {
            dispatchMoveFinished(holder);
            return false;
        } else {
            if (deltaX != 0) {
                view.setTranslationX((float)(-deltaX));
            }

            if (deltaY != 0) {
                view.setTranslationY((float)(-deltaY));
            }

            mPendingMoves.add(new MyCustomItemAnimator.MoveInfo(holder, fromX, fromY, toX, toY));
            return true;
        }
    }

    @Override
    public boolean animateRemove(RecyclerView.ViewHolder holder) {
        //刪除條目動畫實現


        //開始重置動畫
        holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
        endAnimation(holder);

        //把將要執行刪除動畫的ViewHolder放入mPendingRemovals集合
        mPendingRemovals.add(holder);
        return true;
    }

    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
        //改變條目動畫實現


        if (oldHolder == newHolder) {
            return this.animateMove(oldHolder, fromX, fromY, toX, toY);
        } else {
            float prevTranslationX = oldHolder.itemView.getTranslationX();
            float prevTranslationY = oldHolder.itemView.getTranslationY();
            float prevAlpha = oldHolder.itemView.getAlpha();

            //開始重置動畫
            oldHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
            endAnimation(oldHolder);

            int deltaX = (int)((float)(toX - fromX) - prevTranslationX);
            int deltaY = (int)((float)(toY - fromY) - prevTranslationY);
            oldHolder.itemView.setTranslationX(prevTranslationX);
            oldHolder.itemView.setTranslationY(prevTranslationY);
            oldHolder.itemView.setAlpha(prevAlpha);
            if (newHolder != null) {

                //開始重置動畫
                newHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
                endAnimation(newHolder);

                newHolder.itemView.setTranslationX((float)(-deltaX));
                newHolder.itemView.setTranslationY((float)(-deltaY));
                newHolder.itemView.setAlpha(0.0F);
            }

            this.mPendingChanges.add(new MyCustomItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
            return true;
        }
    }

    @Override
    public void runPendingAnimations() {
        boolean removalsPending = !mPendingRemovals.isEmpty();
        boolean movesPending = !mPendingMoves.isEmpty();
        boolean changesPending = !mPendingChanges.isEmpty();
        boolean additionsPending = !mPendingAdditions.isEmpty();
        if (removalsPending || movesPending || additionsPending || changesPending) {
            Iterator var5 = mPendingRemovals.iterator();

            while(var5.hasNext()) {
                RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)var5.next();
                this.animateRemoveImpl(holder);
            }

            mPendingRemovals.clear();
            ArrayList additions;
            Runnable adder;
            if (movesPending) {
                additions = new ArrayList();
                additions.addAll(this.mPendingMoves);
                this.mMovesList.add(additions);
                this.mPendingMoves.clear();
                final ArrayList finalAdditions2 = additions;
                adder = new Runnable() {
                    public void run() {
                        Iterator var1 = finalAdditions2.iterator();

                        while(var1.hasNext()) {
                            MyCustomItemAnimator.MoveInfo moveInfo = (MyCustomItemAnimator.MoveInfo)var1.next();
                            animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, moveInfo.toY);
                        }

                        finalAdditions2.clear();
                        mMovesList.remove(finalAdditions2);
                    }
                };
                if (removalsPending) {
                    View view = ((MyCustomItemAnimator.MoveInfo)additions.get(0)).holder.itemView;
                    ViewCompat.postOnAnimationDelayed(view, adder, this.getRemoveDuration());
                } else {
                    adder.run();
                }
            }

            if (changesPending) {
                additions = new ArrayList();
                additions.addAll(this.mPendingChanges);
                mChangesList.add(additions);
                this.mPendingChanges.clear();
                final ArrayList finalAdditions1 = additions;
                adder = new Runnable() {
                    public void run() {
                        Iterator var1 = finalAdditions1.iterator();

                        while(var1.hasNext()) {
                            MyCustomItemAnimator.ChangeInfo change = (MyCustomItemAnimator.ChangeInfo)var1.next();
                            animateChangeImpl(change);
                        }

                        finalAdditions1.clear();
                        mChangesList.remove(finalAdditions1);
                    }
                };
                if (removalsPending) {
                    RecyclerView.ViewHolder holder = ((MyCustomItemAnimator.ChangeInfo)additions.get(0)).oldHolder;
                    ViewCompat.postOnAnimationDelayed(holder.itemView, adder, this.getRemoveDuration());
                } else {
                    adder.run();
                }
            }

            if (additionsPending) {
                additions = new ArrayList();
                additions.addAll(this.mPendingAdditions);
                this.mAdditionsList.add(additions);
                this.mPendingAdditions.clear();
                final ArrayList finalAdditions = additions;
                adder = new Runnable() {
                    public void run() {
                        Iterator var1 = finalAdditions.iterator();

                        while(var1.hasNext()) {
                            RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)var1.next();
                            animateAddImpl(holder);
                        }

                        finalAdditions.clear();
                        mAdditionsList.remove(finalAdditions);
                    }
                };
                if (!removalsPending && !movesPending && !changesPending) {
                    adder.run();
                } else {
                    long removeDuration = removalsPending ? this.getRemoveDuration() : 0L;
                    long moveDuration = movesPending ? this.getMoveDuration() : 0L;
                    long changeDuration = changesPending ? this.getChangeDuration() : 0L;
                    long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
                    View view = ((RecyclerView.ViewHolder)additions.get(0)).itemView;
                    ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
                }
            }

        }
    }

    @Override
    public void endAnimation(RecyclerView.ViewHolder item) {
        super.endAnimation(item);
    }

    @Override
    public boolean isRunning() {
        //用於判斷動畫是否正在執行
        return super.isRunning();
    }

    @Override
    public void endAnimations() {
        super.endAnimations();
    }

    /**
     * Item狀態改變時的動畫
     * @param changeInfo
     */
    void animateChangeImpl(final MyCustomItemAnimator.ChangeInfo changeInfo) {
        RecyclerView.ViewHolder holder = changeInfo.oldHolder;
        final View view = holder == null ? null : holder.itemView;
        RecyclerView.ViewHolder newHolder = changeInfo.newHolder;
        final View newView = newHolder != null ? newHolder.itemView : null;
        ViewPropertyAnimator newViewAnimation;
        if (view != null) {
            newViewAnimation = view.animate().setDuration(this.getChangeDuration());
            mChangeAnimations.add(changeInfo.oldHolder);
            newViewAnimation.translationX((float)(changeInfo.toX - changeInfo.fromX));
            newViewAnimation.translationY((float)(changeInfo.toY - changeInfo.fromY));
            final ViewPropertyAnimator finalNewViewAnimation = newViewAnimation;
            newViewAnimation.alpha(0.0F).setListener(new AnimatorListenerAdapter() {
                public void onAnimationStart(Animator animator) {
                    dispatchChangeStarting(changeInfo.oldHolder, true);
                }

                public void onAnimationEnd(Animator animator) {
                    finalNewViewAnimation.setListener((Animator.AnimatorListener)null);
                    view.setAlpha(1.0F);
                    view.setTranslationX(0.0F);
                    view.setTranslationY(0.0F);
                    dispatchChangeFinished(changeInfo.oldHolder, true);
                    mChangeAnimations.remove(changeInfo.oldHolder);
                    if (!isRunning()) {
                        dispatchAnimationsFinished();
                    }
                }
            }).start();
        }

        if (newView != null) {
            newViewAnimation = newView.animate();
            this.mChangeAnimations.add(changeInfo.newHolder);
            final ViewPropertyAnimator finalNewViewAnimation1 = newViewAnimation;
            newViewAnimation.translationX(0.0F).translationY(0.0F).setDuration(this.getChangeDuration()).alpha(1.0F).setListener(new AnimatorListenerAdapter() {
                public void onAnimationStart(Animator animator) {
                    dispatchChangeStarting(changeInfo.newHolder, false);
                }

                public void onAnimationEnd(Animator animator) {
                    finalNewViewAnimation1.setListener((Animator.AnimatorListener)null);
                    newView.setAlpha(1.0F);
                    newView.setTranslationX(0.0F);
                    newView.setTranslationY(0.0F);
                    dispatchChangeFinished(changeInfo.newHolder, false);
                    mChangeAnimations.remove(changeInfo.newHolder);
                    if (!isRunning()) {
                        dispatchAnimationsFinished();
                    }
                }
            }).start();
        }

    }

    /**
     * Item移動實現
     * @param holder
     * @param fromX
     * @param fromY
     * @param toX
     * @param toY
     */
    void animateMoveImpl(final RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
        final View view = holder.itemView;
        final int deltaX = toX - fromX;
        final int deltaY = toY - fromY;
        if (deltaX != 0) {
            view.animate().translationX(0.0F);
        }

        if (deltaY != 0) {
            view.animate().translationY(0.0F);
        }

        final ViewPropertyAnimator animation = view.animate();
        this.mMoveAnimations.add(holder);
        animation.setDuration(this.getMoveDuration()).setListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                dispatchMoveStarting(holder);
            }

            public void onAnimationCancel(Animator animator) {
                if (deltaX != 0) {
                    view.setTranslationX(0.0F);
                }

                if (deltaY != 0) {
                    view.setTranslationY(0.0F);
                }

            }

            public void onAnimationEnd(Animator animator) {
                animation.setListener((Animator.AnimatorListener)null);
                dispatchMoveFinished(holder);
                mMoveAnimations.remove(holder);
                if (!isRunning()) {
                    dispatchAnimationsFinished();
                }
            }
        }).start();
    }

    /**
     * 添加Item動畫實現
     * @param holder
     */
    void animateAddImpl(final RecyclerView.ViewHolder holder) {
        final View view = holder.itemView;
        final ViewPropertyAnimator animation = view.animate();
        this.mAddAnimations.add(holder);
        animation.alpha(1.0F).setDuration(this.getAddDuration()).setListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                dispatchAddStarting(holder);
            }

            public void onAnimationCancel(Animator animator) {
                view.setAlpha(1.0F);
            }

            public void onAnimationEnd(Animator animator) {
                animation.setListener((Animator.AnimatorListener)null);
                dispatchAddFinished(holder);
                mAddAnimations.remove(holder);
                if (!isRunning()) {
                    dispatchAnimationsFinished();
                }
            }
        }).start();
    }

    /**
     * 移除Item動畫實現
     * @param holder
     */
    private void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
        final View view = holder.itemView;
        final ViewPropertyAnimator animation = view.animate();
        this.mRemoveAnimations.add(holder);
        animation.setDuration(this.getRemoveDuration()).alpha(0.0F).setListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                dispatchRemoveStarting(holder);
            }

            public void onAnimationEnd(Animator animator) {
                animation.setListener((Animator.AnimatorListener)null);
                view.setAlpha(1.0F);
                dispatchRemoveFinished(holder);
                mRemoveAnimations.remove(holder);
                if (!isRunning()) {
                    dispatchAnimationsFinished();
                }
            }
        }).start();
    }

    private static class MoveInfo {
        public RecyclerView.ViewHolder holder;
        public int fromX;
        public int fromY;
        public int toX;
        public int toY;

        MoveInfo(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
            this.holder = holder;
            this.fromX = fromX;
            this.fromY = fromY;
            this.toX = toX;
            this.toY = toY;
        }
    }

    private static class ChangeInfo {
        public RecyclerView.ViewHolder oldHolder;
        public RecyclerView.ViewHolder newHolder;
        public int fromX;
        public int fromY;
        public int toX;
        public int toY;

        private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder) {
            this.oldHolder = oldHolder;
            this.newHolder = newHolder;
        }

        ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
            this(oldHolder, newHolder);
            this.fromX = fromX;
            this.fromY = fromY;
            this.toX = toX;
            this.toY = toY;
        }

        public String toString() {
            return "ChangeInfo{oldHolder=" + this.oldHolder + ", newHolder=" + this.newHolder + ", fromX=" + this.fromX + ", fromY=" + this.fromY + ", toX=" + this.toX + ", toY=" + this.toY + '}';
        }
    }
}

以上代碼算是照搬DefaultItemAnimator源碼,接下來回基於已整理好的代碼上修改動畫。

【第四步】 修改添加條目動畫

    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        //添加條目動畫實現

        //開始重置動畫
        holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
        endAnimation(holder);

        //讓被添加的條目初始完全透明
        holder.itemView.setAlpha(0.0f);

        //把即將被添加的ViewHolder暫時緩存到mPendingAdditions中
        mPendingAdditions.add(holder);
        return true;
    }

這個方法的執行比較頻繁,這裏保持默認,先重置動畫,再將Item完全透明,最後將ViewHolder添加到mPendingAdditions集合中。

    /**
     * 添加Item動畫實現
     * @param holder
     */
    void animateAddImpl(final RecyclerView.ViewHolder holder) {
        final View view = holder.itemView;
        final ViewPropertyAnimator animation = view.animate();
        this.mAddAnimations.add(holder);
        animation.alpha(1.0F).setDuration(2000).setListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                dispatchAddStarting(holder);
            }

            public void onAnimationCancel(Animator animator) {
                view.setAlpha(1.0F);
            }

            public void onAnimationEnd(Animator animator) {
                animation.setListener((Animator.AnimatorListener)null);
                dispatchAddFinished(holder);
                mAddAnimations.remove(holder);
                if (!isRunning()) {
                    dispatchAnimationsFinished();
                }
            }
        }).start();
    }

animateAddImpl方法基本也沒有變化,只是將動畫時長改成2000ms。

當ViewHolder不可複用時,它的執行效果如下:

當ViewHolder可複用時,它的執行效果如下:

【第五步】 修改位移動畫

位移動畫本身就寫的挺不錯了,這裏偷個懶就只將動畫時間修改爲1秒。

位移動畫主要體現在新增條目和刪除條目上。

效果如下:(由於添加動畫被完全透明瞭,所以這裏只展示ViewHolder被複用的情況)

【第六步】 修改刪除動畫

修改之後的代碼如下:

    /**
     * 移除Item動畫實現
     * @param holder
     */
    private void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
        final View view = holder.itemView;
        final ViewPropertyAnimator animation = view.animate();
        this.mRemoveAnimations.add(holder);
        animation.setDuration(1000)
                .translationX(holder.itemView.getWidth())
                .setInterpolator(new AnticipateOvershootInterpolator())
                .setListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                dispatchRemoveStarting(holder);
            }

            public void onAnimationEnd(Animator animator) {
                animation.setListener((Animator.AnimatorListener)null);
                view.setTranslationX(0);
                dispatchRemoveFinished(holder);
                mRemoveAnimations.remove(holder);
                if (!isRunning()) {
                    dispatchAnimationsFinished();
                }
            }
        }).start();
    }

ViewHolder不可被複用的效果如下:

ViewHolder可被複用的效果如下:

【第七步】 修改狀態改變時的動畫

修改後的代碼如下:

    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
        //改變條目動畫實現

        float prevTranslationX = oldHolder.itemView.getTranslationX();
        float prevTranslationY = oldHolder.itemView.getTranslationY();
        float prevAlpha = oldHolder.itemView.getAlpha();

        //開始重置動畫
        oldHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
        endAnimation(oldHolder);

        int deltaX = (int)((float)(toX - fromX) - prevTranslationX);
        int deltaY = (int)((float)(toY - fromY) - prevTranslationY);
        oldHolder.itemView.setTranslationX(prevTranslationX);
        oldHolder.itemView.setTranslationY(prevTranslationY);
        oldHolder.itemView.setAlpha(prevAlpha);
        if (newHolder != null) {

            //開始重置動畫
            newHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
            endAnimation(newHolder);

            newHolder.itemView.setTranslationX((float)(-deltaX));
            newHolder.itemView.setTranslationY((float)(-deltaY));
            newHolder.itemView.setAlpha(0.0F);
        }

        this.mPendingChanges.add(new MyCustomItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
        return true;
    }

在初始化的時候,oldHolder的透明度保持不變,newHolder給它完全透明。

    /**
     * Item狀態改變時的動畫
     * @param changeInfo
     */
    void animateChangeImpl(final MyCustomItemAnimator.ChangeInfo changeInfo) {
        RecyclerView.ViewHolder holder = changeInfo.oldHolder;
        final View view = holder == null ? null : holder.itemView;
        RecyclerView.ViewHolder newHolder = changeInfo.newHolder;
        final View newView = newHolder != null ? newHolder.itemView : null;
        ViewPropertyAnimator newViewAnimation;
        if (view != null) {
            newViewAnimation = view.animate().setDuration(2000);
            mChangeAnimations.add(changeInfo.oldHolder);
            newViewAnimation.translationX((float)(changeInfo.toX - changeInfo.fromX));
            newViewAnimation.translationY((float)(changeInfo.toY - changeInfo.fromY));
            final ViewPropertyAnimator finalNewViewAnimation = newViewAnimation;
            newViewAnimation.alpha(0.0F).setListener(new AnimatorListenerAdapter() {
                public void onAnimationStart(Animator animator) {
                    dispatchChangeStarting(changeInfo.oldHolder, true);
                }

                public void onAnimationEnd(Animator animator) {
                    finalNewViewAnimation.setListener((Animator.AnimatorListener)null);
                    view.setAlpha(1.0F);
                    view.setTranslationX(0.0F);
                    view.setTranslationY(0.0F);
                    dispatchChangeFinished(changeInfo.oldHolder, true);
                    mChangeAnimations.remove(changeInfo.oldHolder);
                    if (!isRunning()) {
                        dispatchAnimationsFinished();
                    }
                }
            }).start();
        }

        if (newView != null) {
            newViewAnimation = newView.animate();
            this.mChangeAnimations.add(changeInfo.newHolder);
            final ViewPropertyAnimator finalNewViewAnimation1 = newViewAnimation;
            newViewAnimation
                    .setDuration(2000)
                    .alpha(1.0F)
                    .setListener(new AnimatorListenerAdapter() {
                public void onAnimationStart(Animator animator) {
                    dispatchChangeStarting(changeInfo.newHolder, false);
                }

                public void onAnimationEnd(Animator animator) {
                    finalNewViewAnimation1.setListener((Animator.AnimatorListener)null);
                    newView.setAlpha(1.0F);
                    newView.setTranslationX(0.0F);
                    newView.setTranslationY(0.0F);
                    dispatchChangeFinished(changeInfo.newHolder, false);
                    mChangeAnimations.remove(changeInfo.newHolder);
                    if (!isRunning()) {
                        dispatchAnimationsFinished();
                    }
                }
            }).start();
        }

oldHolder透明度從1到0的動畫,newHolder透明度從0到1的動畫,動畫時長爲2000ms,效果如下:

最後,貼出MyCustomItemAnimator類的全部代碼

public class MyCustomItemAnimator extends DefaultItemAnimator {

    //用於存儲將要移動的MoveInfo對象
    private ArrayList<MyCustomItemAnimator.MoveInfo> mPendingMoves = new ArrayList();
    //MoveInfo的臨時存儲集合
    private ArrayList<ArrayList<MyCustomItemAnimator.MoveInfo>> mMovesList = new ArrayList();
    //用於存儲正在執行移動動畫的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mMoveAnimations = new ArrayList();
    //用於存儲將要被添加的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList();
    //存儲被添加的ViewHolder的臨時集合
    private ArrayList<ArrayList<RecyclerView.ViewHolder>> mAdditionsList = new ArrayList();
    //用於存儲正在執行添加動畫的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mAddAnimations = new ArrayList();
    //用於存儲將要刪除的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mPendingRemovals = new ArrayList();
    //用於存儲正在執行刪除動畫的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mRemoveAnimations = new ArrayList();
    //用於存儲將要改變的ViewHolder
    private ArrayList<MyCustomItemAnimator.ChangeInfo> mPendingChanges = new ArrayList();
    //存儲被改變的ViewHolder的臨時集合
    private ArrayList<ArrayList<MyCustomItemAnimator.ChangeInfo>> mChangesList = new ArrayList();
    //用於存儲正在執行改變動畫的ViewHolder
    private ArrayList<RecyclerView.ViewHolder> mChangeAnimations = new ArrayList();

    //定義一個插值器:先向相反方向改變,再加速播放,會超出目標值
    private AnticipateOvershootInterpolator accelerateDecelerateInterpolator;

    @Override
    public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
        return true;
    }


    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        //添加條目動畫實現

        //開始重置動畫
        holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
        endAnimation(holder);

        //讓被添加的條目初始完全透明
        holder.itemView.setAlpha(0.0f);

        //把即將被添加的ViewHolder暫時緩存到mPendingAdditions中
        mPendingAdditions.add(holder);
        return true;
    }


    @Override
    public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
        //移動條目動畫實現

        View view = holder.itemView;
        fromX += (int)holder.itemView.getTranslationX();
        fromY += (int)holder.itemView.getTranslationY();

        //開始重置動畫
        holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
        endAnimation(holder);

        int deltaX = toX - fromX;
        int deltaY = toY - fromY;
        if (deltaX == 0 && deltaY == 0) {
            dispatchMoveFinished(holder);
            return false;
        } else {
            if (deltaX != 0) {
                view.setTranslationX((float)(-deltaX));
            }

            if (deltaY != 0) {
                view.setTranslationY((float)(-deltaY));
            }

            mPendingMoves.add(new MyCustomItemAnimator.MoveInfo(holder, fromX, fromY, toX, toY));
            return true;
        }
    }

    @Override
    public boolean animateRemove(RecyclerView.ViewHolder holder) {
        //刪除條目動畫實現

        //開始重置動畫
        holder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
        endAnimation(holder);

        //把將要執行刪除動畫的ViewHolder放入mPendingRemovals集合
        mPendingRemovals.add(holder);
        return true;
    }

    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
        //改變條目動畫實現

        float prevTranslationX = oldHolder.itemView.getTranslationX();
        float prevTranslationY = oldHolder.itemView.getTranslationY();
        float prevAlpha = oldHolder.itemView.getAlpha();

        //開始重置動畫
        oldHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
        endAnimation(oldHolder);

        int deltaX = (int)((float)(toX - fromX) - prevTranslationX);
        int deltaY = (int)((float)(toY - fromY) - prevTranslationY);
        oldHolder.itemView.setTranslationX(prevTranslationX);
        oldHolder.itemView.setTranslationY(prevTranslationY);
        oldHolder.itemView.setAlpha(prevAlpha);
        if (newHolder != null) {

            //開始重置動畫
            newHolder.itemView.animate().setInterpolator((new ValueAnimator()).getInterpolator());
            endAnimation(newHolder);

            newHolder.itemView.setTranslationX((float)(-deltaX));
            newHolder.itemView.setTranslationY((float)(-deltaY));
            newHolder.itemView.setAlpha(0.0F);
        }

        this.mPendingChanges.add(new MyCustomItemAnimator.ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
        return true;
    }

    @Override
    public void runPendingAnimations() {
        boolean removalsPending = !mPendingRemovals.isEmpty();
        boolean movesPending = !mPendingMoves.isEmpty();
        boolean changesPending = !mPendingChanges.isEmpty();
        boolean additionsPending = !mPendingAdditions.isEmpty();
        if (removalsPending || movesPending || additionsPending || changesPending) {
            Iterator var5 = mPendingRemovals.iterator();

            while(var5.hasNext()) {
                RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)var5.next();
                this.animateRemoveImpl(holder);
            }

            mPendingRemovals.clear();
            ArrayList additions;
            Runnable adder;
            if (movesPending) {
                additions = new ArrayList();
                additions.addAll(this.mPendingMoves);
                this.mMovesList.add(additions);
                this.mPendingMoves.clear();
                final ArrayList finalAdditions2 = additions;
                adder = new Runnable() {
                    public void run() {
                        Iterator var1 = finalAdditions2.iterator();

                        while(var1.hasNext()) {
                            MyCustomItemAnimator.MoveInfo moveInfo = (MyCustomItemAnimator.MoveInfo)var1.next();
                            animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, moveInfo.toY);
                        }

                        finalAdditions2.clear();
                        mMovesList.remove(finalAdditions2);
                    }
                };
                if (removalsPending) {
                    View view = ((MyCustomItemAnimator.MoveInfo)additions.get(0)).holder.itemView;
                    ViewCompat.postOnAnimationDelayed(view, adder, this.getRemoveDuration());
                } else {
                    adder.run();
                }
            }

            if (changesPending) {
                additions = new ArrayList();
                additions.addAll(this.mPendingChanges);
                mChangesList.add(additions);
                this.mPendingChanges.clear();
                final ArrayList finalAdditions1 = additions;
                adder = new Runnable() {
                    public void run() {
                        Iterator var1 = finalAdditions1.iterator();

                        while(var1.hasNext()) {
                            MyCustomItemAnimator.ChangeInfo change = (MyCustomItemAnimator.ChangeInfo)var1.next();
                            animateChangeImpl(change);
                        }

                        finalAdditions1.clear();
                        mChangesList.remove(finalAdditions1);
                    }
                };
                if (removalsPending) {
                    RecyclerView.ViewHolder holder = ((MyCustomItemAnimator.ChangeInfo)additions.get(0)).oldHolder;
                    ViewCompat.postOnAnimationDelayed(holder.itemView, adder, this.getRemoveDuration());
                } else {
                    adder.run();
                }
            }

            if (additionsPending) {
                additions = new ArrayList();
                additions.addAll(this.mPendingAdditions);
                this.mAdditionsList.add(additions);
                this.mPendingAdditions.clear();
                final ArrayList finalAdditions = additions;
                adder = new Runnable() {
                    public void run() {
                        Iterator var1 = finalAdditions.iterator();

                        while(var1.hasNext()) {
                            RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)var1.next();
                            animateAddImpl(holder);
                        }

                        finalAdditions.clear();
                        mAdditionsList.remove(finalAdditions);
                    }
                };
                if (!removalsPending && !movesPending && !changesPending) {
                    adder.run();
                } else {
                    long removeDuration = removalsPending ? this.getRemoveDuration() : 0L;
                    long moveDuration = movesPending ? this.getMoveDuration() : 0L;
                    long changeDuration = changesPending ? this.getChangeDuration() : 0L;
                    long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
                    View view = ((RecyclerView.ViewHolder)additions.get(0)).itemView;
                    ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
                }
            }

        }
    }

    @Override
    public void endAnimation(RecyclerView.ViewHolder item) {
        super.endAnimation(item);
    }

    @Override
    public boolean isRunning() {
        //用於判斷動畫是否正在執行
        return super.isRunning();
    }

    @Override
    public void endAnimations() {
        super.endAnimations();
    }

    /**
     * Item狀態改變時的動畫
     * @param changeInfo
     */
    void animateChangeImpl(final MyCustomItemAnimator.ChangeInfo changeInfo) {
        RecyclerView.ViewHolder holder = changeInfo.oldHolder;
        final View view = holder == null ? null : holder.itemView;
        RecyclerView.ViewHolder newHolder = changeInfo.newHolder;
        final View newView = newHolder != null ? newHolder.itemView : null;
        ViewPropertyAnimator newViewAnimation;
        if (view != null) {
            newViewAnimation = view.animate().setDuration(2000);
            mChangeAnimations.add(changeInfo.oldHolder);
            newViewAnimation.translationX((float)(changeInfo.toX - changeInfo.fromX));
            newViewAnimation.translationY((float)(changeInfo.toY - changeInfo.fromY));
            final ViewPropertyAnimator finalNewViewAnimation = newViewAnimation;
            newViewAnimation.alpha(0.0F).setListener(new AnimatorListenerAdapter() {
                public void onAnimationStart(Animator animator) {
                    dispatchChangeStarting(changeInfo.oldHolder, true);
                }

                public void onAnimationEnd(Animator animator) {
                    finalNewViewAnimation.setListener((Animator.AnimatorListener)null);
                    view.setAlpha(1.0F);
                    view.setTranslationX(0.0F);
                    view.setTranslationY(0.0F);
                    dispatchChangeFinished(changeInfo.oldHolder, true);
                    mChangeAnimations.remove(changeInfo.oldHolder);
                    if (!isRunning()) {
                        dispatchAnimationsFinished();
                    }
                }
            }).start();
        }

        if (newView != null) {
            newViewAnimation = newView.animate();
            this.mChangeAnimations.add(changeInfo.newHolder);
            final ViewPropertyAnimator finalNewViewAnimation1 = newViewAnimation;
            newViewAnimation
                    .setDuration(2000)
                    .alpha(1.0F)
                    .setListener(new AnimatorListenerAdapter() {
                public void onAnimationStart(Animator animator) {
                    dispatchChangeStarting(changeInfo.newHolder, false);
                }

                public void onAnimationEnd(Animator animator) {
                    finalNewViewAnimation1.setListener((Animator.AnimatorListener)null);
                    newView.setAlpha(1.0F);
                    newView.setTranslationX(0.0F);
                    newView.setTranslationY(0.0F);
                    dispatchChangeFinished(changeInfo.newHolder, false);
                    mChangeAnimations.remove(changeInfo.newHolder);
                    if (!isRunning()) {
                        dispatchAnimationsFinished();
                    }
                }
            }).start();
        }

    }

    /**
     * Item移動實現
     * @param holder
     * @param fromX
     * @param fromY
     * @param toX
     * @param toY
     */
    void animateMoveImpl(final RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
        final View view = holder.itemView;
        final int deltaX = toX - fromX;
        final int deltaY = toY - fromY;
        if (deltaX != 0) {
            view.animate().translationX(0.0F);
        }

        if (deltaY != 0) {
            view.animate().translationY(0.0F);
        }

        final ViewPropertyAnimator animation = view.animate();
        this.mMoveAnimations.add(holder);
        animation.setDuration(1000).setListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                dispatchMoveStarting(holder);
            }

            public void onAnimationCancel(Animator animator) {
                if (deltaX != 0) {
                    view.setTranslationX(0.0F);
                }

                if (deltaY != 0) {
                    view.setTranslationY(0.0F);
                }

            }

            public void onAnimationEnd(Animator animator) {
                animation.setListener((Animator.AnimatorListener)null);
                dispatchMoveFinished(holder);
                mMoveAnimations.remove(holder);
                if (!isRunning()) {
                    dispatchAnimationsFinished();
                }
            }
        }).start();
    }

    /**
     * 添加Item動畫實現
     * @param holder
     */
    void animateAddImpl(final RecyclerView.ViewHolder holder) {
        final View view = holder.itemView;
        final ViewPropertyAnimator animation = view.animate();
        this.mAddAnimations.add(holder);
        animation.alpha(1.0F).setDuration(2000).setListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                dispatchAddStarting(holder);
            }

            public void onAnimationCancel(Animator animator) {
                view.setAlpha(1.0F);
            }

            public void onAnimationEnd(Animator animator) {
                animation.setListener((Animator.AnimatorListener)null);
                dispatchAddFinished(holder);
                mAddAnimations.remove(holder);
                if (!isRunning()) {
                    dispatchAnimationsFinished();
                }
            }
        }).start();
    }

    /**
     * 移除Item動畫實現
     * @param holder
     */
    private void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
        final View view = holder.itemView;
        final ViewPropertyAnimator animation = view.animate();
        this.mRemoveAnimations.add(holder);
        animation.setDuration(1000)
                .translationX(holder.itemView.getWidth())
                .setInterpolator(new AnticipateOvershootInterpolator())
                .setListener(new AnimatorListenerAdapter() {
            public void onAnimationStart(Animator animator) {
                dispatchRemoveStarting(holder);
            }

            public void onAnimationEnd(Animator animator) {
                animation.setListener((Animator.AnimatorListener)null);
                view.setTranslationX(0);
                dispatchRemoveFinished(holder);
                mRemoveAnimations.remove(holder);
                if (!isRunning()) {
                    dispatchAnimationsFinished();
                }
            }
        }).start();
    }

    private static class MoveInfo {
        public RecyclerView.ViewHolder holder;
        public int fromX;
        public int fromY;
        public int toX;
        public int toY;

        MoveInfo(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
            this.holder = holder;
            this.fromX = fromX;
            this.fromY = fromY;
            this.toX = toX;
            this.toY = toY;
        }
    }

    private static class ChangeInfo {
        public RecyclerView.ViewHolder oldHolder;
        public RecyclerView.ViewHolder newHolder;
        public int fromX;
        public int fromY;
        public int toX;
        public int toY;

        private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder) {
            this.oldHolder = oldHolder;
            this.newHolder = newHolder;
        }

        ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
            this(oldHolder, newHolder);
            this.fromX = fromX;
            this.fromY = fromY;
            this.toX = toX;
            this.toY = toY;
        }

        public String toString() {
            return "ChangeInfo{oldHolder=" + this.oldHolder + ", newHolder=" + this.newHolder + ", fromX=" + this.fromX + ", fromY=" + this.fromY + ", toX=" + this.toX + ", toY=" + this.toY + '}';
        }
    }
}

[本章完...]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章