support designAndroid学习技术文章

自定义RecyclerView.ItemAnimator其实很简

2017-03-21  本文已影响10437人  锋ivy

RecyclerView是5.0之后新添加的控件,用于在部分方面取代ListViewGridViewRecyclerView耦合性非常低,它不关心视图相关问题。ItemDivideLayoutManager、点击事件、动画等都是可以动态添加,我这次主要来说是RecyclerView.ItemAnimator的分析和自定义。RecyclerView.ItemAnimator主要用于RecyclerViewItem添加、移除、更新时的动画。

那我们要如何自定义呢?现在我们开始分析。

我们平时在使用RecyclerView的时候,没有设置RecyclerView.ItemAnimator时,我们发现RecyclerView在进行Item的操作时,也会存在动画,如下所示:

默认ItemAnimator.gif

从下图可以看出,系统默认为我们设置了DefaultItemAnimator(410行),我们调用setItemAnimator()时,改变的也是mItemAnimator的值,所以我们平时没有设置ItemAnimator时,系统就会执行DefaultItemAnimator的动画效果。

DefaultItemAnimator.png setItemAnimator.png

所以我们要自定义RecyclerView.ItemAnimator,就可以从DefaultItemAnimator入手了,下面我们来看DefaultItemAnimator的源码,一点开这源码的小伙伴可能就要开骂了,说好的很简单呢?600多行代码你和我说简单,走,马上走。但是别急,客官你听我分析下再决定走不走。

DafaultItemAnimator继承的是抽象类SimpleItemAnimatorSimpleItemAnimator主要对动画内部实现进行封装,通过抽象让我们更只关注于更具体的操作,我们定义一个BaseItemAnimator继承SimpleItemAnimator

/**
 * Created by ivy on 2017/3/21.
 * Description:
 */

public class BaseItemAnimator extends SimpleItemAnimator {
    //Item移除回调
    @Override
    public boolean animateRemove(RecyclerView.ViewHolder holder) {
        return false;
    }

    //Item添加回调
    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        return false;
    }


    //用于控制添加,移动更新时,其它Item的动画执行
    @Override
    public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
        return false;
    }

    //Item更新回调
    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
        return false;
    }

    //真正控制执行动画的地方
    @Override
    public void runPendingAnimations() {

    }

    //停止某个Item的动画
    @Override
    public void endAnimation(RecyclerView.ViewHolder item) {

    }

    //停止所有动画
    @Override
    public void endAnimations() {

    }

    @Override
    public boolean isRunning() {
        return false;
    }
}

通过代码我们可以很清楚的知道我们要对哪些情况进行处理,比较难理解的可能是animateMove(),这个方法的作用是在执行某个Item的动画时(update item时是同一个ViewHolder也会调用该方法),其它Item的行为,可以观看上面的Gif,简单来说,比如我们要添加一个Item的位置为1,那么后面的Item要往下移,让出一个空位。

那我们现在就对DafaultItemAnimator按照上面的抽象方法一个个的分析 。#####

首先来看animateRemove()方法,内容很简单就只有2句代码,一句是清除和删除要被移除Item的所有动画的相关代码。第二句是往一个List中添加了当前的ViewHolder,这个mPendingRemovals是什么呢?我们可以看到,类的开始处定义了一系列的List,看名字其实我们也可以猜出他们大概是干什么的,分别是待处理动画、等待运行动画相关数据,正在运行动画的ViewHolder列表。

Paste_Image.png Paste_Image.png

然后我们来看animateAdd()方法,和animateRemove差不多,就多了一句ViewCompat.setAlpha(holder.itemView, 0)代码。我们观看上面的系统默认添加动画可以发现,动画的透明度从0到1出现的,那这句话的作用就很明显了,就是初始化Item的初始动画状态

Paste_Image.png

现在轮到animateMove(final ViewHolder holder, int fromX, int fromY, int toX, int toY)方法了,这个方法有5个参数,分别是要移动的ViewHolder、起始x,y值、目标x,y值。里面执行的操作也很简单,就是把(添加删除更新Item后)目标位置和未执行操作的当前位置的差值计算出来,然后把Item位移到未操作前的现位置

Paste_Image.png

animateChange()方法和animatoMove()方法类似,只是多了一个判断,如果是同一个ViewHolder则直接调用animatoMove(),否则在内部多记录了一个alpha的值

Paste_Image.png

endAnimation(ViewHolder item)方法就是取消指定item的属性动画,然后把上面提到的List(待处理动画、等待运行动画相关数据,正在运行动画的ViewHolder列表)里面的ViewHolder的都移除掉。

endAnimations()方法和endAnimation(ViewHolder item)方法类似,就是循环把List里面的ViewHolder都移除掉,然后把调用cancelAll()方法把所有正在执行的属性动画停止。

Paste_Image.png

isRunning()方法就很简单了,没有执行过多操作,就是判断List是否为空,就知道是否有动画需要执行或者正在执行

Paste_Image.png

最后,我们来看runPendingAnimations(),这个是真正执行动画的地方。首先判断List(Pending)中是否存在待处理动画,如果不存在的话就退出,如果存在就开始依次执行动画。

Paste_Image.png

首先判断是否存在待移除的动画,如果存在,就调用animateRemoveImpl()方法执行属性删除动画,并在动画开始和结束的时候对mRemoveAnimations进行操作,然后清空mRemoveAnimations中的待处理移除动画。

Paste_Image.png Paste_Image.png

move动画和change动画类似,相对于remove动画而言,他就是多了一个判断(151),判断是否需要删除动画的,如果需要,等remove动画执行完毕后再执行move或者chanage动画,否则,直接执行动画。

Paste_Image.png

add动画和move动画类似,只是判断是否需要执行removemovechange动画,如果需要的话,等remove动画和move或者change的动画的最执行时长之和执行完毕后再执行,否则立即执行动画。

Paste_Image.png

到这里,我们就对默认的DefaultItemAnimator动画就分析完毕了,我们也了解内部是怎么实现的。对如何实现自己的RecyclerView.ItemAnimator也有了一个大概的思路。

下一步,就让我们来定义自己的RecyclerView.ItemAnimator。#####
上一篇下一篇

猜你喜欢

热点阅读