自定义RecyclerView.ItemAnimator其实很简单(上)

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

推荐阅读更多精彩内容

  • 这篇文章分三个部分,简单跟大家讲一下 RecyclerView 的常用方法与奇葩用法;工作原理与ListView比...
    LucasAdam阅读 4,361评论 0 27
  • 简介: 提供一个让有限的窗口变成一个大数据集的灵活视图。 术语表: Adapter:RecyclerView的子类...
    酷泡泡阅读 5,125评论 0 16
  • RecyclerView包含以下几个重要的组件:1.LayoutManager: 测量和布局子View2.Recy...
    乌龟爱吃肉阅读 3,507评论 4 7
  • “点赞”这个词对于生活在互联网时代的人来说是再熟悉不过的了。君不见那微信朋友圈上发出来的任何一条信息都会获得若...
    石妈妈阅读 345评论 0 1
  • 2016年11月21日 周一 下午老叔来电话说:房子已经租完,买煤盘电炕,窗户蒙上塑料布等等准备工作在老亲少友的帮...
    魅力春天阅读 153评论 0 1