自定义RecyclerView.ItemAnimator其实很简
RecyclerView
是5.0之后新添加的控件,用于在部分方面取代ListView
和GridView
。RecyclerView
耦合性非常低,它不关心视图相关问题。ItemDivide
、LayoutManager
、点击事件、动画等都是可以动态添加,我这次主要来说是RecyclerView.ItemAnimator
的分析和自定义。RecyclerView.ItemAnimator
主要用于RecyclerView
的Item
添加、移除、更新时的动画。
那我们要如何自定义呢?现在我们开始分析。
我们平时在使用RecyclerView
的时候,没有设置RecyclerView.ItemAnimato
r时,我们发现RecyclerView
在进行Item
的操作时,也会存在动画,如下所示:
![](https://img.haomeiwen.com/i837800/28ce81ca88b12494.gif)
从下图可以看出,系统默认为我们设置了DefaultItemAnimator
(410行),我们调用setItemAnimator()
时,改变的也是mItemAnimator
的值,所以我们平时没有设置ItemAnimator
时,系统就会执行DefaultItemAnimator
的动画效果。
![](https://img.haomeiwen.com/i837800/418cdbad320c818f.png)
![](https://img.haomeiwen.com/i837800/0564bc45e30bd741.png)
所以我们要自定义RecyclerView.ItemAnimator
,就可以从DefaultItemAnimator
入手了,下面我们来看DefaultItemAnimator
的源码,一点开这源码的小伙伴可能就要开骂了,说好的很简单呢?600多行代码你和我说简单,走,马上走。但是别急,客官你听我分析下再决定走不走。
DafaultItemAnimator
继承的是抽象类SimpleItemAnimator
,SimpleItemAnimator
主要对动画内部实现进行封装,通过抽象让我们更只关注于更具体的操作,我们定义一个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
列表。
![](https://img.haomeiwen.com/i837800/426a3e0a876c5c9f.png)
![](https://img.haomeiwen.com/i837800/e48c53a1a0e0f91c.png)
然后我们来看animateAdd()
方法,和animateRemove
差不多,就多了一句ViewCompat.setAlpha(holder.itemView, 0)
代码。我们观看上面的系统默认添加动画可以发现,动画的透明度从0到1出现的,那这句话的作用就很明显了,就是初始化Item
的初始动画状态
![](https://img.haomeiwen.com/i837800/640bb0281d6731d8.png)
现在轮到animateMove(final ViewHolder holder, int fromX, int fromY, int toX, int toY)
方法了,这个方法有5个参数,分别是要移动的ViewHolder
、起始x,y
值、目标x,y
值。里面执行的操作也很简单,就是把(添加删除更新Item
后)目标位置和未执行操作的当前位置的差值计算出来,然后把Item
位移到未操作前的现位置
![](https://img.haomeiwen.com/i837800/f6d754e766fad4be.png)
animateChange()
方法和animatoMove()
方法类似,只是多了一个判断,如果是同一个ViewHolder
则直接调用animatoMove()
,否则在内部多记录了一个alpha
的值
![](https://img.haomeiwen.com/i837800/8701491a4d464fe5.png)
endAnimation(ViewHolder item)
方法就是取消指定item
的属性动画,然后把上面提到的List
(待处理动画、等待运行动画相关数据,正在运行动画的ViewHolder
列表)里面的ViewHolder
的都移除掉。
endAnimations()
方法和endAnimation(ViewHolder item)
方法类似,就是循环把List
里面的ViewHolder
都移除掉,然后把调用cancelAll()
方法把所有正在执行的属性动画停止。
![](https://img.haomeiwen.com/i837800/adbf29f413607892.png)
isRunning()
方法就很简单了,没有执行过多操作,就是判断List
是否为空,就知道是否有动画需要执行或者正在执行
![](https://img.haomeiwen.com/i837800/6028e8774b202627.png)
最后,我们来看runPendingAnimations()
,这个是真正执行动画的地方。首先判断List(Pending)
中是否存在待处理动画,如果不存在的话就退出,如果存在就开始依次执行动画。
![](https://img.haomeiwen.com/i837800/5e047b24e1455b17.png)
首先判断是否存在待移除的动画,如果存在,就调用animateRemoveImpl()
方法执行属性删除动画,并在动画开始和结束的时候对mRemoveAnimations
进行操作,然后清空mRemoveAnimations
中的待处理移除动画。
![](https://img.haomeiwen.com/i837800/468b4d083e7c09cb.png)
![](https://img.haomeiwen.com/i837800/e96053b519247810.png)
move
动画和change
动画类似,相对于remove
动画而言,他就是多了一个判断(151),判断是否需要删除动画的,如果需要,等remove
动画执行完毕后再执行move
或者chanage
动画,否则,直接执行动画。
![](https://img.haomeiwen.com/i837800/ccec550fbec2bfe7.png)
add
动画和move
动画类似,只是判断是否需要执行remove
、move
和change
动画,如果需要的话,等remove
动画和move
或者change
的动画的最执行时长之和执行完毕后再执行,否则立即执行动画。
![](https://img.haomeiwen.com/i837800/62529ffe3a915737.png)
到这里,我们就对默认的DefaultItemAnimator
动画就分析完毕了,我们也了解内部是怎么实现的。对如何实现自己的RecyclerView.ItemAnimator
也有了一个大概的思路。