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