android recyclerview grid 分割线

recyclerview 系统提供了默认的分割线。调用很方便。

不过,这里的系统默认分割线其实只针对类似 listview/或者是横向listview这种场景去使用的。

对于 gridview 模式下,使用默认的分割线就不能达到预期效果了。

针对这个问题,我参考了系统默认分割线的源码,提供了一种解决方案,感觉还是蛮好用的。

先看一下效果图:
在这里插入图片描述

关键代码如下:

	private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
        canvas.save()
        var left: Int
        val right: Int

        var itemRight = 0

        if (parent.clipToPadding) {
            left = parent.paddingLeft
            right = parent.width - parent.paddingRight
            canvas.clipRect(
                left, parent.paddingTop, right,
                parent.height - parent.paddingBottom
            )
        } else {
            @Suppress("UNUSED_VALUE")
            left = 0
            right = parent.width
        }

        val childCount = parent.childCount
        LogUtils.e("child count = $childCount")
        for (i in 0 until childCount) {
            var count = ((i + 1) % spanCount)
            count = if (count == 0) spanCount else count
            // LogUtils.w("$i , $count")
            itemRight = count * right / spanCount
            left = (count - 1) * right / spanCount
            val child = parent.getChildAt(i)
            parent.getDecoratedBoundsWithMargins(child, mBounds)
            val bottom = mBounds.bottom + child.translationY.roundToInt()
            val top = bottom - mDivider!!.intrinsicHeight
            mDivider!!.setBounds(left, top, itemRight, bottom)
            mDivider!!.draw(canvas)
        }
        canvas.restore()
    }

    private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) {
        canvas.save()
        var top: Int
        val bottom: Int

        var itemHeight = 0
        if (parent.clipToPadding) {
            top = parent.paddingTop
            bottom = parent.height - parent.paddingBottom
            canvas.clipRect(
                parent.paddingLeft, top,
                parent.width - parent.paddingRight, bottom
            )
        } else {
            top = 0
            bottom = parent.height
        }

        val childCount = parent.childCount
        LogUtils.e("child count = $childCount")

        var line = 0
        val totalLine = childCount / spanCount + if (childCount % spanCount > 0) 1 else 0
        for (i in 0 until childCount) {
            if ((i + 1) % (spanCount) == 1) {
                line += 1
            }
            itemHeight = bottom * line / totalLine
            top = bottom * (line - 1) / totalLine
            LogUtils.w("$i , $line , $itemHeight")
            val child = parent.getChildAt(i)
            parent.layoutManager!!.getDecoratedBoundsWithMargins(child, mBounds)
            val right = mBounds.right + child.translationX.roundToInt()
            val left = right - mDivider!!.intrinsicWidth
            mDivider!!.setBounds(left, top, right, itemHeight)
            mDivider!!.draw(canvas)
        }
        canvas.restore()
    }
    
    override fun getItemOffsets(
        outRect: Rect, view: View, parent: RecyclerView,
        state: RecyclerView.State
    ) {
        if (mDivider == null) {
            outRect.set(0, 0, 0, 0)
            return
        }
        when (mOrientation) {
            VERTICAL -> {
                outRect.set(0, 0, 0, mDivider!!.intrinsicHeight)
            }
            HORIZONTAL -> {
                outRect.set(0, 0, mDivider!!.intrinsicWidth, 0)
            }
            STAGGEREDGRID -> {
                outRect.set(0, 0, mDivider!!.intrinsicWidth, mDivider!!.intrinsicHeight)
            }
        }
    }

由于主要是源码,这里只是做了少量修改,就不加注释了。简单解释一下:

首先系统方法drawVerticaldrawHorizontal 实现是有点简单粗暴的。看里面有一个循环,根据每个 item 去画分割线,但是开始位置总是 left=0 或者top=0,然后 right=parent.right 或者parent.bottom
1. 如果是列表类型的,没什么问题,这样只会导致前面的分割线被多次覆盖,不影响效果。
2. 但是,由于现在是想绘制grid模式的,那么, right=parent.right 或者parent.bottom 会导致后面不存在的item,也被绘制分割线了。
3. 所以,每次绘制的时候确定起始点和结束点,就可以做到grid效果了。

源文件:GridItemDecoration.kt

使用 kotlin 去实现的,抱歉。
我理解 javaer 看 kotlin 的痛苦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值