关注 ItemDecoration 是因为我前阵子在分析 RecyclerView 内部实现原理时看到有相关的代码逻辑。之前对它的印象是用来做列表装饰,但感觉不太好用,现在想着尝试用它主要还是为了优化列表元素实现分割线的效果。
用 Item 布局实现分割线
按照之前一贯的实现思路,列表里所有的视觉都由 Item 的布局来实现,通过业务逻辑控制来展示数据。而分割线这块是预先做好布局,然后在 onBindViewHolder 方法里通过遍历判断元素在列表里的位置,例如不是最后一个就展示分割线,最后一个不展示。
其实不太喜欢这么实现,但也找不到更合适的,也就一直这么用。缺点在于,不同列表 Item 布局都要去考虑分割线的布局,还有代码实现,而这部分实现纯粹是体力活,费力不说,代码上其实也不太合理,为了展示一根线要做集合遍历,感觉不划算。
用 ItemDecoration 实现分割线
首先通过继承 RecyclerView.ItemDecoration 实现自己的子类,并在 getItemOffsets() 方法里设置间距。这个间距分为上下左右四个方向,要做分割线,可以考虑 bottom 的值,
//Kotlin 实现
outRect.bottom = context.resources.getDimensionPixelSize(R.dimen.1dp)
这 1dp 的空间撑开后就能为后面的分割线展示预留位置了,接着在 onDraw() 方法里绘制一个同样大小的矩形,来展示分割线效果。要注意的是,这个方法里需要遍历 RecyclerView 的 Item 元素,并在满足展示条件的情况下绘制矩形。
完成上面两步,就完成了分割线装饰的配置,最后只要 RecyclerView 调用相应 set 方法就可以展示。
相比之前用布局实现有什么好处呢?职责区分开,和业务无关的就从业务逻辑代码中剥离。效果可复用,一般一个应用会是一套主题效果,这样配置后,别的列表要分割线只要调用 set 方法就可以了,还用每次做 item 布局时考虑分割线吗。
另外 ItemDecoration 除了实现分割线效果,也还有其他效果可以做。
ItemDecoration
前面实现了分割线效果涉及到两个方法,其实 ItemDecoration 需要关心的方法就 3 个(包括上面说的两个),这里再简单梳理下,
//控制 item view 四周的偏移量,通过 outRect 这个矩形区域控制
//例如我想在每个 view 的底部留出 1 dp,那么就赋值 outRect 的 bottom 为 1dp
//这样底部空间就出来了
getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State)
//看名字就知道这个是用来画的,但区别是入参不像 getItemOffsets,它没有提供 item view
//所以这里才需要遍历,参考文章中说它是以 RecyclerView 的维度来调用的
//画画的话通过 Canvas 对象,所以什么都能画
onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State)
//也是画画,但会浮于 RecyclerView 之上,所以它是可以做一个浮层效果的
//除此之外和 onDraw 就没什么区别了
//参考文章中的吸顶效果就需要用到这个方法
onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State)
对于吸顶效果的实现我之前也试着实现过,但觉得都比较的重,需要控制位置,以及吸顶布局的显示与隐藏,而用 ItemDecoration 实现起来非常轻松。不过我觉得这种实现还是偏向于展示,如果要带操作交互可能就不太合适了。
参考内容
RecyclerView之ItemDecoration由浅入深
小甜点,RecyclerView 之 ItemDecoration 讲解及高级特性实践
RecyclerView探索之通过ItemDecoration实现StickyHeader效果
网友评论