继上一篇: RecyclerView中Decoration解读,就只能做分割占位了吗
最近看的知识点大致分为两个方向,一个是Kotlin,一个是自定义view,所以笔记写的就很杂,当然了主要还是一次性把一个东西学完学会,这里面消耗的心力和脑力是很大的。所以交叉着多次学习,Kotlin 学了到自定义view上可能又有使用的地方。所以,今天又来卡着一天的最后一两个小时写笔记了,这有一种刀尖舔血的魅力感。OK,那就开整
正文
上一篇blog,大致是对ItemDecoration 进行了简单的使用,比如说调用次数,层级划分等等。当然了还有额外的扩展空间,其实我有时候看到ItemDecoration的时候也会想这个玩意还能做啥。恰好,今天在翻阅启航大佬的《Android自定义控件高级进阶与精彩实例》这本书的时候,看到了大佬在该书的第7章里面提供了很多的思路,那么就尝试整一下,所以,这笔记里面很多东西都是在借鉴大佬这本书,嗯,大佬还写了一本书《Android自定义控件开发入门与实战》感觉也很细,都很适合填充一些自己的知识点盲区。
getItemOffsets中Rect对于整个recyclerView的影响
上一篇的demo 里面,当我们列表是上下滚动的,那么我们对于rect的设置是:
css
// left top right bottom
outRect.set(0, 0, 0, 10))
我们只是对于bottom设置了10px。想要了解这个玩意的效果,最好还是理解一下Rect这个对象的在canvas使用上的含义。这里就需要偷一张图了:
又回到那个问题了,图看懂了,有啥关系吗? 那么我们就把每一个都设置10,然后分割线填充颜色。
bash
outRect.set(10, 10, 10, 10)
那么来看效果图:
可以看到左右有10px的间距了,而且我们第一行的头上也有了10px,第2行和第1行之间的间距变成了20。单纯从效果上看,我们就可以知道,这个layoutManger计算item的绘制位置的时候,一定是获取了rect对象的参数的。在RecyclerView的measureChild的函数里面确实在获取这个调调,所以这个rect是可以影响整个的recycler的布局的,那么我们脑洞大一点,左右动态的呢?
kotlin
override fun getItemOffsets(outRect: Rect, itemPosition: Int, parent: RecyclerView) {
outRect.set(10*itemPosition, 10, 10*itemPosition, 5)
}
我们随着item的position的增加,左右也增加。

emmm? 果真要这样吗?既然如此大佬书中的效果就很容易理解了。下面几种效果不就是计算位置自定义view了吗?

绘制区域内容
我们再来回顾一下onDraw的入参。
less
onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State)
recyclerview都拿到了,我们还拿不到什么?而且canvas是整个recyclerview 区域。我们再来回顾一下,之前绘制分割线的时候怎么确定分割线的位置的。
scss
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(canvas, parent, state)
canvas.save()
// 剩下的就是复制 DividerItemDecoration.drawVertical() 的代码,然后进行更改就行。
val left: Int
val right: Int
if (parent.clipToPadding) {
left = parent.paddingLeft
right = parent.width - parent.paddingRight
canvas.clipRect(
left, parent.paddingTop, right,
parent.height - parent.paddingBottom
)
} else {
left = 0
right = parent.width
}
val childCount = parent.childCount
val startX = paddingHorizontal + left
val stopX = right - paddingHorizontal
LogUtils.e(stopX)
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
// 获取item的margins
parent.getDecoratedBoundsWithMargins(child, mBounds)
val bottom = mBounds.bottom + child.translationY
val top = bottom - lineHeight+paddingVertical
val rect=Rect(startX.toInt(),top.toInt(),stopX.toInt(),(bottom-paddingVertical).toInt())
//paint.color=lineColor
// 通过矩形绘制
canvas.drawRect(rect,paint)
// 通过线条绘制
//paint.color=Color.RED
//canvas.drawLine(startX,rect.centerY().toFloat(),stopX,rect.centerY().toFloat(),paint)
}
canvas.restore()
}
其中getDecoratedBoundsWithMargins很关键,它确定了我们需要绘制的分割线的位置。那么我们是不是也可以计算出这个item的y轴上的中间位置。为了确定这个的具体位置,直接实现onDrawOver:
kotlin
override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(canvas, parent, state)
canvas.save()
paint.color=Color.GREEN
val child = parent.getChildAt(0)
parent.getDecoratedBoundsWithMargins(child, mBounds)
// 通过矩形绘制
canvas.drawRect(mBounds,paint)
canvas.restore()
}

可以看到,mbounds 所在空间其实是包含了我们所需要绘制分割线的空间的,所以,可以基于mBounds 去确定item的y轴的中间位置。
结束
因为是基于书上的内容,还是需要自己去看书,大致需要的逻辑,其实已经捋的比较细了,比如说确定位置,比如说如何让item不遮挡我们canvas所画的内容都又涉及到,demo 代码还是在上一篇中的分支里面。看完大佬的书,感觉真的限制我们的只有想象力,当然想象力完全依托于认知,所以提升认知还是任重道远的。