RecyclerView随V7拓展包发布以来,因其高效和使用便利,基本取代了listview和gridview,成为了使用频率最高的控件之一。默认的设置基本能满足大部分场景,如果需要更好的体验,需要自定义以下三个部分的内容:
自定义Animator
自定义Animator可以实现各种绚丽的动画效果,RecyclerView动画相关的类主要有三个:
RecyclerView.ItemAnimator是自定义RecyclerView动画效果的核心类,当继承一个ItemAnimator时,有如下几个方法需要被实现:
SimpleItemAnimator对RecyclerView.ItemAnimator实现了简单的封装,将基本的ItemAnimator不同场景拆分成我们熟悉的四种场景:add、remove、move、change。所以我们如果实现自定义的动画,继承自SimpleItemAnimator会更容易实现,这也是较为普遍的做法。
DefaultItemAnimator是RecyclerView默认的动画效果,只有一个fadein和fadeout的渐变动画,开始看代码的时候一直有一个疑问,默认的动画效果明明是一个先展开然后插入的动画啊,哪里是渐变的效果。对比了各种动画效果之后发现,这里实现的动画效果只是针对item出现或者消失时的动画,位置展开是RecylerView固定的效果,具体代码没有去源码中跟踪,调用notifyItemInserted函数刷新界面时,先执行对应位置的展开再执行item的动画效果,我们自定义动画就是实现这个item出现的方式,位置展开和收缩是固定的。V7拓展包23.0版本DefaultItemAnimator继承自RecyclerView.ItemAnimator,23.1版本就直接继承自SimpleItemAnimator。
我们参照DefaultItemAnimator的方式实现我们自定义的动画效果。其中最主要的删除和新增实现如下:
其中写死了animation的效果,而又无法重载,我们将DefaultItemAnimator的代码完全拷出,实现一个可配置动画的BaseItemAnimator类。主要替换的代码如下:
接下来我们就可以继承BaseItemAnimator类实现自己的动画效果,下面给出一个示例:
详细代码见github
自定义ItemDecoration
自定义ItemDecoration需要继承RecyclerView.ItemDecoration抽象类,源码很简单:
官方推荐使用含有state参数的方法,所以主要就是重载三个方法:
- onDraw(Canvas c, RecyclerView parent, State state)
- onDrawOver(Canvas c, RecyclerView parent, State state)
- getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)
onDraw用于绘制divider,它是绘制在item下面的,所以中间部分会被item遮挡住;
onDrawOver绘制在item上面,所以不受位置的限制;
getItemOffsets实际上就是给每个item一个padding,实现item之间的间隙。
实际业务中我们经常会遇到这样的需求,一个可选择的gridview,选中与否有不同的边框,效果图如下:
以我有限的界面开发经验,不管如何控制,要实现每个分割线都是相同的宽度,选中界面的边框正好压盖周围的边框还是很有难度的,看到recyclerview的自定义ItemDecoration才终于发现一道曙光。
我的做法是在getItemOffsets函数中,我判断一个item上下左右是否有临近的item,没有的话给两倍的dividerwidth,否则一倍的dividerwidth,这样就能控制所有的item四周都是有同样宽度的间隙。然后在onDrawOver中实现每个item分割线的绘制,同时判断是否选中,再绘制选中的边框,整体效果如下:
还是完美的实现了UI妹子要求的效果(^_^)。
详细代码见github
自定义LayoutManager
LayoutManager可以说是整个RecyclerView的精髓,整个RecyclerView的Recycler也是在LayoutManager做的,官方目前提供了LinearLayoutManager、GridLayoutManager和StaggeredGridLayoutManager三种LayoutManager,分别使用在线性、方格以及不规则瀑布流的场景,基本上实现了日常的大部分需求。目前精力有限,后续再做分解。