RecycleView Grid样式的分割线,均分每行

说明

最近写一个GridView的布局,需要一个较宽的分割线样式,发现自己以前写的还有网上的很多都有问题,主要存在没考虑到divider也有一定宽度,这样导致第一行特别宽,其他行都较短。
特修改bug,顺便分享一下

原理

其实很简单,主要就是在 重新 ItemDecoration 的 getItemOffsets方法
给设置每块的布局添加偏移量padding,注释都在里面

totalwidth = 总列数 X 每列宽度 + (总列数 - 1)X Divider宽度

RecycleView Grid样式的分割线,均分每行_第1张图片

完整代码如下:

/**
 * 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)
    }

}

你可能感兴趣的:(Android,UI,解决问题,ui,android)