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不可复用时,它的执行效果如下:

136.gif

当ViewHolder可复用时,它的执行效果如下:

138.gif

【第五步】 修改位移动画

位移动画本身就写的挺不错了,这里偷个懒就只将动画时间修改为1秒。

位移动画主要体现在新增条目和删除条目上。

效果如下:(由于添加动画被完全透明了,所以这里只展示ViewHolder被复用的情况)

139.gif

【第六步】 修改删除动画

修改之后的代码如下:

    /**
     * 移除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不可被复用的效果如下:

141.gif

ViewHolder可被复用的效果如下:

140.gif

【第七步】 修改状态改变时的动画

修改后的代码如下:

    @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,效果如下:

142.gif

最后,贴出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 + '}';
        }
    }
}

[本章完...]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容