RecyclerView使用GridLayoutManager时,分区域显示背景

要实现的效果:

使用一个GridLayoutManager,将item分成title和normal两种类型,title的spanSize是3,normal的spanSize是1。
每个区域的上下边距和区域内的边距长度稍有不同

image

实现思路:

遍历view,如果是每一列的第一个view就继续
判断条目是标题还是要画背景的条目,如果是要画背景的条目,判断条目所在位置。
具体情况分为:1. 该行是一块里面的第一行、中间行、最后行 2. 该行是独立的一块
分情况画背景

实现代码:


class AiInsuranceAllToolsItemDecoration : ItemDecoration() {
    override fun onDraw(
        c: Canvas, parent: RecyclerView,
        state: RecyclerView.State
    ) {
        val childCount = parent.childCount
        for (ix in 0 until childCount) {
            val child = parent.getChildAt(ix)
            val position = parent.getChildAdapterPosition(child)
            val layoutManager = parent.layoutManager as GridLayoutManager
            val spanCount = layoutManager.spanCount
            val spanSizeLookup = layoutManager.spanSizeLookup
            val spanSize = spanSizeLookup.getSpanSize(position)
            val spanIndex = spanSizeLookup.getSpanIndex(
                position,
                spanCount
            )
            if (spanSize != 1 || spanIndex != 0) {
                continue
            }
            /*
             * title不画
             * 普通的判断每一行的第一个
             *    如果在第一行 且行数>1 画上半部分  第一行 判断,上一个的spanCount是3
             *    如果在第一行 且行数=1 画圆       行数是否>1 判断position+1 +2 +3的spanSize都是1
             *    如果在第一行往后 且后面还有 画方块 行数>1判断
             *    如果在最后一行 画下半部分         行数>1判断
             * */
            val hasNextLine = hasNextLine(spanSizeLookup, position, spanCount)
            val hasLastLine = hasLastLine(spanSizeLookup, position, spanCount)
            val type = if (hasLastLine) {
                if (hasNextLine) {
                    // 方块
                    2
                } else {
                    // 最后一行
                    3
                }
            } else {
                // 没有上一行
                if (hasNextLine) {
                    // 第一行
                    1
                } else {
                    // 最后一行
                    0
                }
            }
            val drawable = generateDrawable(type)
            drawable.setBounds(
                child.left,
                if (hasLastLine) child.top else child.top - mOutSize,
                child.left + child.width * spanCount,
                if (hasNextLine) child.bottom else child.bottom + mOutSize
            )
            drawable.draw(c)
        }
    }

    private fun hasLastLine(
        spanSizeLookup: GridLayoutManager.SpanSizeLookup,
        position: Int,
        spanCount: Int
    ): Boolean {
        // 3个以内发现占位是3的标题,就是没有上一行
        for (i in 1..spanCount) {
            if (spanSizeLookup.getSpanSize(position - i) != 1) {
                return false
            }
        }
        return true
    }

    private fun hasNextLine(
        spanSizeLookup: GridLayoutManager.SpanSizeLookup,
        position: Int,
        spanCount: Int
    ): Boolean {
        // 判断3个以内第一个group不一样的条目的spanSize
        val spanGroupIndex = spanSizeLookup.getSpanGroupIndex(position, spanCount)
        for (i in 1..spanCount) {
            if (spanSizeLookup.getSpanGroupIndex(position + i, spanCount) != spanGroupIndex) {
                return spanSizeLookup.getSpanSize(position + i) == 1
            }
        }
        return true
    }

    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        super.getItemOffsets(outRect, view, parent, state)
        // 每一组的第一排top+15 最后一排bottom+15
        val position = parent.getChildAdapterPosition(view)
        val gridLayoutManager = parent.layoutManager as GridLayoutManager
        val spanSizeLookup = gridLayoutManager.spanSizeLookup
        val spanSize = spanSizeLookup.getSpanSize(position)
        if (spanSize != 1) {
            return
        }
        val spanCount = gridLayoutManager.spanCount
        val hasLastLine = hasLastLine(spanSizeLookup, position, spanCount)
        val hasNextLine = hasNextLine(spanSizeLookup, position, spanCount)
        if (!hasLastLine) {
            // 第一排
            outRect.top = mOutSize
        }
        if (!hasNextLine) {
            outRect.bottom = mOutSize
        }
    }

    private val mCornerRadius: Float = getApplication().dimenPxOffset(R.dimen.x20).toFloat()
    private val mOutSize: Int = getApplication().dimenPxOffset(R.dimen.x15)

    /**
     * /外矩形 0 四角圆弧 1 上半部分  2 方块  3 下半部分
     */
    private fun generateDrawable(type: Int): GradientDrawable {
        val gd = GradientDrawable()
        gd.cornerRadii = when (type) {
            0 -> floatArrayOf(
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
            )
            1 -> floatArrayOf(
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
                0F,
                0F,
                0F,
                0F,
            )
            2 -> floatArrayOf(
                0F,
                0F,
                0F,
                0F,
                0F,
                0F,
                0F,
                0F,
            )
//            3,
            else -> floatArrayOf(
                0F,
                0F,
                0F,
                0F,
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
                mCornerRadius,
            )
        }
        gd.setColor(Color.WHITE)
        return gd
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • PK赛 第六天 今天上午注定是难熬的一上午,早早起床又空讲了2遍,然后早早到了比赛场地,准备室被前几个讲课的用着的...
    一日三省吾身阅读 1,001评论 0 2
  • 浙江省公共数据条例 日期: 2022- 02- 10 18: 25 来源: 浙江省人民代表大会常务委员会 浙江省公...
    33d686a71aaa阅读 1,443评论 0 0
  • 流程结构 条件语句当成程序中设定某一个条件满足才执行的语句 if(条件语句){代码段1}else{代码段2}条件语...
    胖胖胖虎阅读 1,553评论 0 0
  • 像操作一部机器那样,进行管理,以实现目标。 5个步骤,1树立目标,2发现问题,3诊断练发现问题根源,4设计改进方案...
    Rite_芳姐姐阅读 2,755评论 0 0
  • 初识山姆 我说的山姆不是人物,也不是地名,更不是动物,而是美国的一个大型购物超市。 山姆与Costco是同类型的,...
    大翁阅读 2,870评论 4 5