RecyclerView的ItemAnimator
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RecyclerView的ItemAnimator相关的知识,希望对你有一定的参考价值。
参考技术A ItemAnimator有2个实现类,分别为SimpleItemAnimator和DefaultItemAnimator, 记录了holder.itemView的边界,决定着item是否可以移动,改变,移除的动画,提供了基础的添加,移除,移动动画。以animateChange为例,看下如何实现的,之前的RecyclerView分析已经讲了什么场景会执行到这里。preInfo 就是layout之前的holder的info ,postInfo 就是holder真正layout之后的info。animateChange最终实现在DefaultItemAnimator中。
1、动画执行之前,设置初始值,记录,mPendingChanges.add()。
oldViewHolder设置:它本身的TranslationX/Y和Alpha。
newViewHolder设置:newHolder设置为 toX - fromX - prevTranslatonX 和alpha为0,如果oldholder和newHolder的位置重合,则这个值为0。
假如希望有个move的效果,ToX的值是不可能变的,我们可以改变fromX的值,比如在调用notifyItemChange之前,设置fromX的值为holder.item的宽度,也就是设置holder.itemView的left值。
2、依次执行动画,设置结束值,runPendingAnimations()。
因为item改变,分为olderView离开和newView出现,所以对应2个动画。
oldViewHolder设置 : oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX); 如果new和old的位置不变,则changeInfo.toX - changeInfo.fromX的值为0,不会有位移效果。只有alpha会从1变成0。
newViewHolder设置: 从初始位置到translationX(0)。alpha从0到1。
同样,如果需要位移效果,改FromX的值,调用notifyitemChange的时候,把holder的left改了,就有move效果了。
3、测试下改了FromX的效果。
主要用于特殊View的绘制和偏移的view,还可以绘制分割线,高亮,可视化边界。
1、绘制特殊的View。如下2个方法。
onDraw(Canvas, RecyclerView, RecyclerView.State) 在item绘制之前。
onDrawOver(Canvas, RecyclerView, RecyclerView.State) 在item绘制之后。
以绘制vertical为例,left和right是确定的。绘制每一个child的botttom或者top即可。
parent.getDecoratedBoundsWithMargins(child, mBounds); mBounds包含了child的位置和大小(包含margin和decorated insert),所以mBouns.bottom - mDivider.getIntrinsicHeight() 就是top。也就是绘制分割线的top值。
2、偏移view。
getItemOffsets(Rect , int ,RecyclerView) measure的时候,会把Decoration的大小计算在view所需的大小中。
可以通过getChildAdapterPosition(View)拿到adapter position 然后给指定的position设置分割线等。
ItemTouchHelper 也是继承自ItemDecoration,并且重写了onDraw()方法,加入了拖拽Dx,Dy偏移量,方便在拖拽过程中,我们可以改变recyclerView中item的展示效果,依据dy执行缩放等。类似卡片,先在onlayoutchildren中布局完成,在childDraw中执行拖拽动画。
1、如果调用了notifyDatasetChanged但是layout还没完成,此时getAdapterPostion为-1 。
2、当item被删除了,或者viewholder已经被回收,getAdapterPostion返回-1。
3、layoutmanager中,应该使用getLayoutPostion参与计算,比如用户需要第五个位置的item。在adapter中,应该使用getAdapterPosition,比如点击。
RecyclerView.ItemAnimator实现动画效果
Item动画来源
在RecyclerView的源码中,有一个ItemHolderInfo.java。其源码如下:
ItemHolderInfo主要是用来表示RecyclerView中item的信息。
图中①处表示这个类主要是和实现Item的动画效果有关
图中②处表示开发人员可以继承这个类,并保存额外的Item信息,最终实现更多的动画效果
图中③处表示,开发人员可以复写obtainHolderInfo方法来返回自定义的ItemHolderInfo对象
那这个obtainHolderInfo是在哪里调用的呢?
+
在RecyclerView中搜索obtainHolderInfo方法,只有两个地方调用了obtainHolderInfo方法:
可以看出分别被两个recordXXXLayoutInfomation方法调用,在RecyclerView中再搜索这两个方法,发现他们分别在RecyclerView布局阶段的dispatchLayoutStep1和dispatchLayoutStep3这两个方法调用:
解释说明:
dispatchLayoutStep1中记录的是RecyclerView布局子ItemView之前的信息,因此此时记录的是重新布局之前的ViewHolder信息。
dispatchLayoutStep2方法中会执行具体的布局子ItemView的操作。
dispatchLayoutStep3中再次记录的布局之后新的ViewHolder信息。
并且最终recordPre和recordPost返回的2个自定义ItemHolderInfo都会被保存到ViewInfoStore中。
ViewInfoStore保存preInfo和postInfo
+
其源码如下:
解释说明:
内部维护了一个ArrayMap键值对,key为ViewHolder类型,value为InfoRecord类型。
在InfoRecord中保存了通过preRecord和postRecord传入的自定义ItemHolderInfo对象。
有了preInfo和postInfo之后,
这两个对象用来干嘛呢?
+
在ViewInfoStore中还有一个非常重要的方法---process(ProcessCallback, callback),具体如下:
在 RecyclerView.ItemAnimator源码解析 这篇文章中我已经分析过,图中红框中的各个process方法最终会调用开发人员自定义ItemAnimator的各个animate方法。比如animateChange方法中的preLayoutInfo和postLayoutInfo就是在此处设置的,如下所示:
实现自定义动画效果
源码了解了之后,接下来就开始一步步实现动画效果。先看一下最终实现的动画效果,点击RecyclerView中的某一个Item时,被点击的Item会通过自转效果实现刷新操作。如下所示:
1 自定义ItemHolderInfo对象
代码如下:
2 自定义ItemAnimator对象
我直接继承系统自带的DefaultItemAnimator,并分别复写recorPreLayoutInformation和recordPostLayoutInformation方法,如下:
通过调用super方法先将ItemView中的left、right、top、bottom等信息保存到ColorTextInfo中,然后通过getItemHolderInfo方法设置ViewHolder的color和text。该方法代码如下:
最后按照官方的说明,我们需要在自定义ItemAnimator中,复写 obtainHolderInfo方法返回自定义的ItemHolderInfo对象,如下所示:
大功告成!这样就实现了RecyclerView的Item动画效果。
实际上,我们可以在自定义ItemHolderInfo中创建更多的信息,并实现更多的动画效果,具体还要看项目中的需求。完整代码关注公众号,发送私信 "rv2" 获取。
如果你喜欢本文
长按二维码关注
点个赞,证明你还爱我
以上是关于RecyclerView的ItemAnimator的主要内容,如果未能解决你的问题,请参考以下文章
Android L 中的 RecyclerView ItemAnimator 故障
RecyclerView.ItemAnimator实现动画效果