【译】RecyclerView专题之item动画实现原理(一)

原文 http://www.birbit.com/recyclerview-animations-part-1-how-animations-work/

Listview 是Android最受欢迎的控件之一,虽然它有许多特性,但是它也是相当复杂并且很难修改.
在Lollipop中,Android发布了一个新的控件--RecyclerView,它的插件化结构使得展现collection views更加简单,仅仅通过实现一些简单的contract就可以实现很多不同的功能:
1.how item are laid out
2.item animator
3.item decorations
4.recycling strategy

Predictive Animation

在这篇文章中,我想去深入剖析RecyclerView的内部实现原理,尤其是关于动画是如何实现的.
在Honeycomb中,Android 引入了布局动画LayoutTransition,来实现当ViewGroup布局变化时的过渡动画.这个框架会拿到ViewGroup布局变化前后的状态,然后在两种状态间创建动画进行改变.
但是,列表控件与普通ViewGroup有很大的区别,列表控件中的item与ViewGroup中的子view也有很大的区别,所以我们不能直接使用LayoutTransition.在普通ViewGroup中,如果View是被新加入到ViewGroup中的,它是被当做一个新的View对待的,并且可以使用fade in等动画.但是对于列表,例如,一个item的view变成可见的,可能是因为它前面的item从Adapter中被移除了.在这种情况下,如果使用fade in动画,就会让用户产生改item是被新插入的错觉,但是事实上这个item已经在列表中了,它应该是滚入屏幕的.RecyclerView知道这个item是否是新的,但是却不知道当这个item它原来的位置在哪.同样的,对于滚出屏幕的item(前提没有被adapter移除),RecyclerView同样不知道这个view要被放置在哪.

image.png

LayoutTransition failure for a list
RecyclerView如果通过LayoutManger拿到新View的的previous位置,那么LayoutManager不仅需要做一些记录的工作还要多出一些计算的工作.
那么RecyclerView是如何处理这种item的出现和消失动画的呢(指的是那些滚出/滚入屏幕的item)?没错,就是依赖LayoutManager,
LayoutManager通过处理预布局(predictive layout logic)的逻辑,来向RecyclerView提供变化前后item的位置.当Adapter发生改变时,RecyclerView使用了两次Layout处理:
1.第一次Layout(preLayout),RecyclerView会向LayoutManager提供一些信息,让LayoutManager对改变前的状态进行一次layout.
以上面的动图为例,LayoutManager会收到C将要被移除的信息,然后进行layout(将C留下的位置补上),整个环节最重要的部分就
是RecyclerView假装C仍在Adapter中.比如,当LayoutManager要获取index为2的view时,RecyclerView要返回‘C’.
2.第二次Layout(postLayout),RecyclerView让LayoutManager重新布局items,这次‘C’已经被Adapter移除,getViewForPosition(2)拿
到的是‘D’,getViewForPosition(4)拿到的是‘F’.Keep in mind that the backing item for 'C' was already removed from the Adapter,
but since RecyclerView has the View representation of it, it can behave as if 'C' is still there. In other words, RecyclerView
does the bookkeeping for the LayoutManager.
LayoutManger每次调用onLayoutChildren时,它都会暂时detach掉所有的View然后在进行布局,未发生改变的View之前的measure还是有效的,所以这中relayout是很cheap和simple的.

image.png

LinearLayoutManager pre layout result: (pink rectangle marks the area visible to the user)*

image.png

LinearLayoutManager post layout
在两次布局之后,RecyclerView就可以知道了View的previous location,然后进行正确的动画.

image.png

Predictive animation
你也许会问:LayoutManager没有对‘C’的view进行laid out,为什么C还是可见的?
事实上,'C'在pre_layout中是被LayoutManager lai'd out了,但是在post-layout没有被laid out因为它已经不再Adapter中了.它也确实不再是LayoutManager的child,但是它却仍旧是RecyclerView的child,所以此时ItemAnimator可以正常的执行.

Disappearing Items
但是现在还有一个问题就是,将要消失的item.考虑下面这个例子,有一个item被加入到列表中,会将另一个item退出屏幕外.下面是用LayoutTransition实现的效果:

image.png

Add Animation Failure

当‘X’被添加到‘A’的后面,F会被挤出屏幕外.LayoutTransition认为‘F’已经被移除,然后对F使用了Fade out 动画.但事实上F仍在列表中.
为了解决这个问题,RecyclerView给LayoutManger提供了API来获取这个信息.在第二次Layout的最后(postLayout),LayoutManager可以调用getScrapList()方法获取那些不会被LayoutManager布局但是却仍旧在Adapter中的Views.然后LayoutManager会假设RecyclerView大到可以展示这些View,对这些View进行lay out.

image.png

LinearLayoutManager post layout
这有一个很重要的细节就是,对于那些在动画结束后不再有用的View,LayoutManger会通过调用addDisappearingView而不是addView来告诉RecyclerView,这个View在动画结束后应该被移除.RecyclerView也会添加这个View到the list of hidden views,当postLayout方法返回时,这个View就会被从LayoutManager的children list中被移除.
也许你会认为,对于LinearLayoutManager来说,完全可以单独计算View原来的位置或者将要被放置的的位置,也不必进行两次Layout操作.但是对于有多个item类型的Adapter,如果多个类型同时发生改变,会产生许多临界情况.此外,对于像StaggeredGridLayout这种复杂的LayoutManager,计算item的位置是很繁琐的.目前的这种方式,可以减轻LayoutManager的负担,仅仅需要一点代价就可以完成动画.


image.png

Predictive Add Animation

,

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,464评论 25 707
  • 简介: 提供一个让有限的窗口变成一个大数据集的灵活视图。 术语表: Adapter:RecyclerView的子类...
    酷泡泡阅读 5,137评论 0 16
  • 我喜欢着很多人,我只深爱着你。
    xhhbj阅读 240评论 0 1
  • 以前很想要两个宝宝,一男一女最好了。刚开始工作找杭州的时候觉得这是可以实现的,目前工作找到了上海,被这高房价高消费...
    花儿的博文阅读 122评论 0 0