说明
最近写一个GridView的布局,需要一个较宽的分割线样式,发现自己以前写的还有网上的很多都有问题,主要存在没考虑到divider也有一定宽度,这样导致第一行特别宽,其他行都较短。
特修改bug,顺便分享一下
原理
其实很简单,主要就是在 重新 ItemDecoration 的 getItemOffsets方法
给设置每块的布局添加偏移量padding,注释都在里面
totalwidth = 总列数 X 每列宽度 + (总列数 - 1)X Divider宽度
完整代码如下:
/**
* grid recycleview 分割线
* attention:
* 1,不处理header和footer中的divider
* 2,不绘制外边框
* 3,考虑到了每行除去divider的宽度被行元素平分
*/
class GridDividerLine : ItemDecoration {
private var mDivider: Drawable
private var dividerHeight = DensityUtil.dip2px(5)
private var spanCount = 0
constructor(context: Context) {
val a: TypedArray = context.obtainStyledAttributes(ATTRS)
mDivider = a.getDrawable(0)
a.recycle()
}
constructor(
context: Context, @ColorRes colorId: Int, dividerHeight: Int) {
mDivider = ColorDrawable(context.resources.getColor(colorId))
this.dividerHeight = dividerHeight
}
override fun onDrawOver(
c: Canvas, parent: RecyclerView, state: State) {
super.onDrawOver(c, parent, state)
spanCount = getSpanCount(parent)
drawHorizontal(c, parent)
drawVertical(c, parent)
}
private fun getSpanCount(parent: RecyclerView): Int {
// 列数
var spanCount = -1
val layoutManager = parent.layoutManager
if (layoutManager is GridLayoutManager) {
spanCount = layoutManager.spanCount
} else if (layoutManager is StaggeredGridLayoutManager) {
spanCount = layoutManager.spanCount
}
return spanCount
}
fun drawHorizontal(
c: Canvas, parent: RecyclerView) {
val childCount = parent.childCount
val startIndex = 0
val endIndex = childCount
for (i in startIndex until endIndex) {
val child: View = parent.getChildAt(i)
val params = child.layoutParams as LayoutParams
val left = child.left - params.leftMargin
val right = child.right + params.rightMargin + dividerHeight
val top = child.bottom + params.bottomMargin
val bottom = top + dividerHeight
//每个元素的下边分割线
mDivider.setBounds(left, top, right, bottom)
LogUtils.d("GridDividerLine", "drawHorizontal:$left, $top, $right, $bottom")
mDivider.draw(c)
}
}
fun drawVertical(
c: Canvas, parent: RecyclerView) {
val childCount = parent.childCount
val startIndex = 0
val endIndex = childCount
for (i in startIndex until endIndex) {
val child: View = parent.getChildAt(i)
val params = child.layoutParams as LayoutParams
val top = child.top - params.topMargin
val bottom = child.bottom + params.bottomMargin
val left = child.right + params.rightMargin
val right = left + dividerHeight//mDivider.getIntrinsicWidth();
//每个元素的右边分割线
mDivider.setBounds(left, top, right, bottom)
mDivider.draw(c)
}
}
override fun getItemOffsets(
outRect: Rect, view: View, parent: RecyclerView, state: State) {
super.getItemOffsets(outRect, view, parent, state)
var spanCount = getSpanCount(parent)
if (spanCount == 0) {
return
}
// 如果是最后一行,则不需要绘制底部
val itemPosition = parent.getChildLayoutPosition(view)
var row = itemPosition / spanCount
var column = itemPosition % spanCount
// 保证 各个column平分每一行 total = n * column + (n - 1) * divider
//左侧为(当前条目数-1)/总条目数*divider宽度
outRect.left = column * dividerHeight / spanCount
//右侧为(总条目数-当前条目数)/总条目数*divider宽度
outRect.right = (spanCount - column - 1) * dividerHeight / spanCount
outRect.top = if (row == 0) 0 else dividerHeight
outRect.bottom = 0
}
companion object {
private val ATTRS = intArrayOf(attr.listDivider)
}
}