最近遇到了一个需求,在recycler view上面添加一个header view,可以随着recycler view一起滚动。咋一看起来这个需求好像没什么问题,搜一下recycler view header,一堆一堆”RecyclerView添加header正确方式”的博客文章。翻看了一下,也到gayhub找各种recycler view header相关的开源库,基本上实现方式都是使用ViewType区分header view和item view,在最上面放置一个不同于其他item的header view。
以上这种实现方式具体的示例就不写了,可以自行搜索。
在了解完这种实现方式后,再看详细需求,header view要固定第一个item上面、不可点击、不可被选中、不可获得焦点。
如果用常用的ViewType来做header view的话,由于其他item都需要可点击可选中可获得焦点,header要实现上面的需求就要做比较多的特殊处理,于是想到了ItemDecoration
。
ItemDecoration的功能是为Recycler View的item做装饰,item的边距就可以使用它做很好的控制,并且这种装饰本身就是不可点击不可选中不可获得焦点的,那只要做一个可以固定在第一个item上面的ItemDecoration即可,使用时很方便就能通过Recycler View addItemDecoration()
方法添加,不需要在adapter中做更多的特殊处理。
RecyclerView.ItemDecoration
这个类包含三个方法:
onDraw(Canvas c, RecyclerView parent, State state)
onDrawOver(Canvas c, RecyclerView parent, State state)
getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)
这里用尽量简单的总结描述帮助大家理解这三个方法。
getItemOffsets:
每一个子view在设置itemDecoration的时候都会进入这个回调,可以通过设置第一个参数Rect,为子view增加padding值,例如outRect.set(10,20,30,40)
,即为子view左边距增加10,上边距增加20,右边距增加30,下边距增加40。
为什么要增加边距?
是否增加边距可以由开发者自己决定。
如果绘制的装饰内容是在item的上下左右空白处,则为item增加边距再绘制装饰才不会遮盖住item原本显示的内容。
如果绘制的装饰内容是直接遮盖在item上面的,例如为item绘制半透明遮罩,这种情况则不需要为item增加边距。
onDraw 以及 onDrawOver:
关于这两个方法的原理,这里不会太具体的解释,只需要记住: decoration 的 onDraw,child view 的 onDraw,decoration 的 onDrawOver,这三者是依次发生的。
也就是说,onDraw绘制的内容会在子item的下面,onDrawOver绘制的内容会在子item的上面,至于装饰内容要放在下面被子item覆盖,还是要放在上面覆盖子item由具体场景决定。
ItemDecoration详细原理请参考:
深入理解 RecyclerView 系列之一:ItemDecoration
HeaderDecoration代码
import android.content.Context;
import android.graphics.Canv