Kotlin--›Android 超轻,超好用,超简洁,超超超级RecyclerView分割线ItemDecoration封装

2023-05-16

在这里插入图片描述

需求分析

如图所示的:

  1. 101(共2人) 这一行, 顶部有 一块白色区域, 可以当做是分割线
  2. 101(共2人) 这一行, 底部有一个很细的分割线, 差不多撑满了一行
  3. 人物信息 这一行, 首次出现时, 只有底部有分割线, 而且还是 非撑满一行的效果
  4. 人物信息 这一行, 最后出现时, 底部没有分割线

不出意外, 很多同学的实现方式, 都是在 布局的xml中, 用padding maring backgroud 实现.

但是遇到这种相同type类型的item, 只有中间有分割线, 最后一条没有分割线的情况, 估计就有点棘手了.

莫慌, 看完本文, 你能轻松应对各种恶心的分割线.

具体实现

继承 RecyclerView.ItemDecoration , 实现 核心的 getItemOffsets onDraw onDrawOver 方法, 通常 只需要实现 getItemOffsets onDraw 即可. 如果需要悬停效果, 才需要实现 onDrawOver

为了让封装更轻量, 所以, 我并打算有任何实际操作方法.
只做核心业务的封装, 具体实现 丢给调用者.

    override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        eachChildViewHolder(parent) { beforeViewHolder, viewHolder, afterViewHolder ->
            eachItemDoIt.invoke(canvas, parent, state, null, beforeViewHolder, viewHolder, afterViewHolder, false)
        }
    }

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        eachChildViewHolder(parent, view) { beforeViewHolder, viewHolder, afterViewHolder ->
            eachItemDoIt.invoke(null, parent, state, outRect, beforeViewHolder, viewHolder, afterViewHolder, false)
        }
    }

核心方法

    fun eachChildViewHolder(
        parent: RecyclerView,
        targetView: View? = null,/*指定目标, 则只回调目标前后的ViewHolder*/
        callback: (
            beforeViewHolder: RecyclerView.ViewHolder?,
            viewHolder: RecyclerView.ViewHolder,
            afterViewHolder: RecyclerView.ViewHolder?
        ) -> Unit
    ) {

        val childCount = parent.childCount
        for (i in 0 until childCount) {
            val child = parent.getChildAt(i)
            val childViewHolder = parent.findContainingViewHolder(child)

            childViewHolder?.let {

                //前一个child
                var beforeViewHolder: RecyclerView.ViewHolder? = null
                //后一个child
                var afterViewHolder: RecyclerView.ViewHolder? = null

                if (i >= 1) {
                    beforeViewHolder = parent.findContainingViewHolder(parent.getChildAt(i - 1))
                }
                if (i < childCount - 1) {
                    afterViewHolder = parent.findContainingViewHolder(parent.getChildAt(i + 1))
                }

                if (targetView != null) {
                    if (targetView == child) {
                        callback.invoke(beforeViewHolder, it as RBaseViewHolder, afterViewHolder)
                        return
                    }
                } else {
                    callback.invoke(beforeViewHolder, it as RBaseViewHolder, afterViewHolder)
                }
            }
        }
    }

通过此方法, 到RecyclerView触发onDraw时, 枚举界面上的所有childView, 并且计算拿到 前一个后一个 childViewviewHolder 对象.(如果有)

这样就可以通过 ViewHolder.getItemViewType 来区分, 各个item的类型, 也能够通过,
前一个比较, 判断是否是同类型的第一个位置
后一个比较, 判断是否是同类型的最后一个位置

有个你想要的各种信息, 绘制分割线的事, 就交给 canvas 吧.

完整代码

class DslItemDecoration : RecyclerView.ItemDecoration() {

    val paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
    val tempDrawRect = Rect()

    /**
     * 将3个方法, 合一调用. 通过参数, 来区分是那一个方法.
     *
     * outRect 不为空时, 是 getItemOffsets 方法
     * canvas 不为空时, 是 onDrawOver onDraw
     * isOverDraw 控制是否是 onDrawOver
     * */
    var eachItemDoIt: (
        canvas: Canvas?, parent: RecyclerView, state: RecyclerView.State, outRect: Rect?,
        beforeViewHolder: RecyclerView.ViewHolder?,
        viewHolder: RecyclerView.ViewHolder,
        afterViewHolder: RecyclerView.ViewHolder?,
        isOverDraw: Boolean
    ) -> Unit =
        { _, _, _, _, _, _, _, _ -> }

    override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        eachChildRViewHolder(parent) { beforeViewHolder, viewHolder, afterViewHolder ->
            eachItemDoIt.invoke(canvas, parent, state, null, beforeViewHolder, viewHolder, afterViewHolder, true)
        }
    }

    override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        eachChildRViewHolder(parent) { beforeViewHolder, viewHolder, afterViewHolder ->
            eachItemDoIt.invoke(canvas, parent, state, null, beforeViewHolder, viewHolder, afterViewHolder, false)
        }
    }

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        eachChildRViewHolder(parent, view) { beforeViewHolder, viewHolder, afterViewHolder ->
            eachItemDoIt.invoke(null, parent, state, outRect, beforeViewHolder, viewHolder, afterViewHolder, false)
        }
    }

    fun eachChildViewHolder(
        parent: RecyclerView,
        targetView: View? = null,/*指定目标, 则只回调目标前后的ViewHolder*/
        callback: (
            beforeViewHolder: RecyclerView.ViewHolder?,
            viewHolder: RecyclerView.ViewHolder,
            afterViewHolder: RecyclerView.ViewHolder?
        ) -> Unit
    ) {

        val childCount = parent.childCount
        for (i in 0 until childCount) {
            val child = parent.getChildAt(i)
            val childViewHolder = parent.findContainingViewHolder(child)

            childViewHolder?.let {

                //前一个child
                var beforeViewHolder: RecyclerView.ViewHolder? = null
                //后一个child
                var afterViewHolder: RecyclerView.ViewHolder? = null

                if (i >= 1) {
                    beforeViewHolder = parent.findContainingViewHolder(parent.getChildAt(i - 1))
                }
                if (i < childCount - 1) {
                    afterViewHolder = parent.findContainingViewHolder(parent.getChildAt(i + 1))
                }

                if (targetView != null) {
                    if (targetView == child) {
                        callback.invoke(beforeViewHolder, it as RBaseViewHolder, afterViewHolder)
                        return
                    }
                } else {
                    callback.invoke(beforeViewHolder, it as RBaseViewHolder, afterViewHolder)
                }
            }
        }
    }
}

调用例子

public fun RecyclerView.dslItemDecoration(init: DslItemDecoration.() -> Unit) {
    addItemDecoration(DslItemDecoration().apply {
        init()
    })
}
dslItemDecoration {
   val line = getDimen(R.dimen.wt_line)
   eachItemDoIt = { canvas, _, _, outRect, _, viewHolder, afterViewHolder, _ ->
       if (viewHolder.itemViewType == R.layout.item_info_group_head) {
           outRect?.set(0, 10 * dpi, 0, line)

           tempDrawRect.set(
               0,
               viewHolder.itemView.top - 10 * dpi,
               viewHolder.itemView.right,
               viewHolder.itemView.top
           )
           paint.color = getColor(R.color.wt_dark_bg)
           canvas?.drawRect(tempDrawRect, paint)

           tempDrawRect.set(
               0,
               viewHolder.itemView.top - line,
               viewHolder.itemView.right,
               viewHolder.itemView.top
           )
           paint.color = getColor(R.color.wt_line)
           canvas?.drawRect(tempDrawRect, paint)

           tempDrawRect.set(
               0,
               viewHolder.itemView.bottom,
               viewHolder.itemView.right,
               viewHolder.itemView.bottom - line
           )
           canvas?.drawRect(tempDrawRect, paint)

       } else if (viewHolder.itemViewType == R.layout.item_info_single_text) {
           if (afterViewHolder?.itemViewType == R.layout.item_info_single_text) {
               outRect?.set(0, 0, 0, line)

               paint.color = getColor(R.color.wt_line)
               tempDrawRect.set(
                   25 * dpi,
                   viewHolder.itemView.bottom,
                   viewHolder.itemView.right,
                   viewHolder.itemView.bottom - line
               )

               canvas?.drawRect(tempDrawRect, paint)
           }
       }
   }
}

结束…


群内有各(pian)种(ni)各(jin)样(qun)的大佬,等你来撩.

联系作者

点此快速加群

请使用QQ扫码加群, 小伙伴们都在等着你哦!

关注我的公众号, 每天都能一起玩耍哦!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Kotlin--›Android 超轻,超好用,超简洁,超超超级RecyclerView分割线ItemDecoration封装 的相关文章

  • ONVIF协议--ONVIF协议简介

    1 ONVIF简介 网络摄像机是网络设备 xff0c 需要有通讯协议 xff0c 早期的网络摄像机硬件提供商都采用私有协议 随着视频监控的网络化应用 xff0c 产业链的分工将越来越细 有些厂商专门做摄像头 xff0c 有些厂商专门做视频服
  • GB28181协议--GB28181协议简介

    1 GB T 28181 2016协议简介 近年来 xff0c 国内视频监控应用发展迅猛 xff0c 系统接入规模不断扩大 xff0c 涌现了大量平台提供商 xff0c 平台提供商的接入协议各不相同 xff0c 终端制造商需要给每款终端维护
  • 网络基础--UPnP基本原理

    1 简介 UPnP是通用即插即用 xff08 Universal Plug and Play xff09 的缩写 xff0c 主要用于设备的智能互联互通 xff0c 使用UPnP协议不需要设备驱动程序 xff0c 它可以运行在目前几乎所有的
  • 数学基础--高斯分布详解

    1 简介 正态分布 xff08 Normal Distribution xff09 xff0c 又名高斯分布 xff08 Gaussian Distribution xff09 xff0c 是一个在数学 物理及工程等领域都非常重要的概率分布
  • GB28181协议--流媒体的几种传输方式(UDP、TCP被动、TCP主动模式)

    1 简介 根据 GB T 28181 2016 4 3 1 5 2的要求 xff0c SIP和流媒体都应该支持TCP和UDP两种方式 如下图所示 xff1a 在附录F xff08 SDP 定义 xff09 中介绍了TCP支持主动模式和被动模
  • GB28181协议--校时

    1 简介 根据 GB T 28181 2016 7 10 9 10的要求 xff0c GB28181设备网络校时功能描述如下 xff1a 联网系统内的IP 网络服务器设备宜支持 NTP 见IETF RFC2030 协议的网络统一校时服务 网
  • GB28181协议--报警

    1 简介 根据 GBT 28181 2016 公共安全视频监控联网系统信息传输 交换 控制技术要求 9 4节的 报警事件通知和分发基本要求 描述 xff1a 发生报警事件时 源设备应将报警信息发送给 SIP 服务器 SIP 服务器接收到报警
  • AS--›Android Studio安装教程

    文章目录 前言下载官方智能下载地址官方手动下载地址 安装运行常见问题Android SDK安装JVM启动失败卡在启动页重装软件 推荐阅读联系作者 前言 android studio是Google官方推荐的Android开发工具 以前用的是E
  • GB28181协议--SIP协议介绍

    1 SIP协议简介 SIP xff08 Session Initiation Protocol xff0c 会话初始协议 xff09 是一个用于建立 更改和终止多媒体会话的应用层控制协议 xff0c 其中的会话可以是IP电话 多媒体会话或多
  • 代码管理--svnadmin工具介绍

    1 简介 SVNAdmin2 是一款通过图形界面管理服务端SVN的web程序 正常情况下配置SVN仓库的人员权限需要登录到服务器手动修改 authz 和 passwd 两个文件 xff0c 当仓库结构和人员权限上了规模后 xff0c 手动管
  • 深度学习--FAISS向量数据库

    简介 我们日常使用的各种 APP 中的许多功能 xff0c 都离不开相似度检索技术 比如一个接一个的新闻和视频推荐 各种常见的对话机器人 保护我们日常账号安全的风控系统 能够用哼唱来找到歌曲的听歌识曲 xff0c 甚至就连外卖配送的最佳路线
  • 腾讯云4核8G服务器性能怎么样?

    腾讯云4核8G云服务器的价位硬件配置性能指标怎么样 如何买便宜呢 4核8G云服务器是中大型商业网站及服务采用的实例规格 xff0c 能够 承载每日几十万浏览量的网站服务 当一个企业网站发展到这一程度的情况下 xff0c 针对云服务器成本费用
  • networkx画图

    使用networkx画图 xff0c 关键是掌握draw networkx edges draw networkx nodes和draw networkx labels三个方法的使用 xff0c 设置好位置列表 xff0c 节点列表 xff
  • virt-manager cannot open display

    解决方法 xff1a 1 vi etc ssh sshd config 2 找到 34 X11Forwarding no 34 修改为 34 X11Forwarding yes 34 3 service sshd restart 4 重启终
  • 【蓝牙模块】三款常用的基础蓝牙模块,HC05,JDY-31,CC2541介绍与测试说明

    文章目录 一 HC05二 JDY 311 介绍2 测试 二 CC2541 一 HC05 HC05与其他两款的区别是 xff0c 需要按住RST键进入AT指令模式 一 上电进入AT模式方法 先按住HC05蓝牙模块上面的RST按键 xff0c
  • #Ubuntu#SSH 新建虚拟机开启SSH服务

    由于Ubuntu默认未安装SSH服务 xff0c 所以需要通过联网下载安装SSH服务 前置条件 xff1a Ubuntu需要配置好网络地址 xff0c 并配置正确的DNS服务器 xff0c 能够正常上网 1 右键打开终端界面 xff0c 输
  • #Ubuntu#root 新建虚拟机怎么切换到root用户权限

    我现在新建了一台ubuntu xff0c 需要通过切换到root用户执行文件 xff0c 发现怎么切换都是失败的 通过su root命令 xff0c 输入普通用户的密码 xff0c 会显示认证错误 xff0c 百度了一下 xff0c 这是由
  • Gradle--›Spring Kotlin多模块项目搭建√

    文章目录 前言使用IntelliJ IDEA创建单模块工程搭建多模块环境创建主模块创建库模块 部署参考文档联系作者 前言 环境说明 工具版本IntelliJ IDEAUltimate 2021 1SpringBoot2 5 0Kotlin1
  • #华为 #usg 华为防火墙安全区域的概念

    简介 安全区域 xff08 Security Zone xff09 xff0c 或者简称为区域 xff08 Zone xff09 xff0c 是设备所引入的一个安全概念 xff0c 大部分的安全策略都基于安全区域实施 定义 一个安全区域是若
  • #VMware ESXI7.0的下载

    一 VMware ESXI7 0版本的下载 xff08 一 xff09 概述 VMware vSphere是VMware公司推出的服务器虚拟化解决方案 xff0c 包含两个重量级的产品 xff1a VMware ESXI和VMware vC

随机推荐

  • #VMware#ESXI 配置虚拟机服务器开机自启动

    目录 1 登录到esxi xff0c 配置管理模块 2 将虚拟机配置开机启动 3 返回主机管理界面 xff0c 完成配置 4 停电后重启主机 xff0c 查看并验证自启动是否生效 1 登录到esxi xff0c 配置管理模块 选择管理 系统
  • #VMware#ESXI ESXI如何修改管理IP

    目录 一 修改方法 1 进入硬件管理平台 2 登录虚拟控制台 二 实际操作 1 在主界面按 F2 并输入控制台界面root的密码 xff0c 进入设置界面 2 找到 configure Management Network 选项并按 Ent
  • #华为 #usg USG6000双链路透明部署实验(一)

    目录 一 实验背景 二 实验环境 三 实验步骤 1 在所有交换机创建对应vlan 2 在核心交换机创建网关 xff0c 所有的网段IP都是254 网段是10 10 10 0 24 10 10 13 0 24 3 配置接入交换机的管理IP x
  • #VMware#ESXI 修改主机的控制台HTTP/HTTPS端口

    目录 一 开启SSH服务 二 修改控制台的默认端口 1 关闭防火墙的情境下 xff1a 1 1 远程进入ESXI的后台 xff0c 修改HTTP端口配置文件 1 2 关闭ESXI防火墙 1 3 重启服务器 2 不关闭防火墙的情景下 xff1
  • #ESXI #Centos 业务服务器故障如何恢复盘

    一 环境描述 有一台centos7的业务服务器 xff0c 因为操作人员重大失误 xff0c 导致业务服务器宕机 xff0c 由于未做备份与快照 xff0c 无法进行恢复 xff0c 考虑通过将硬盘挂载在其他虚拟机上重新获取数据 设备环境为
  • pikachu 靶场搭建

    一 准备环境 1 搭建环境 win 10phpstudypikachu 2 下载链接 win10自行寻找资源 pickchu靶机下载地址 xff1a https github com zhuifengshaonianhanlu pikach
  • virtualbox命令行启动虚拟机和关闭虚拟机和虚拟机关闭防火墙

    查看virtualbox正在运行的虚拟机命令 VBoxManage list runningvms 根据查到的虚拟机 ip 号 使用后台命令启动虚拟机的方法 xff1a VBoxManage startvm ip 使用后台命令关闭虚拟机的方
  • android studio 最新3.0 kotlin与databinding 结合使用报错。

    最近android studio 3 0更新 xff0c 迫不及待将项目中的代码向kotlin转 其中转到有databinding的时候遇到报错 xff1a Unresolved reference databinding 找到网上解决办法
  • AS--›Android Studio内存大小设置和插件推荐(2021-1-14更新)

    调整AS的占用内存 多开工程毫无压力 AS 3 5 的版本 已经支持通过设置界面修改内存大小了 但是 旧方法依旧有效 文章目录 Windows修改方法MAC修改方法插件推荐 ignore A Search with GithubTransl
  • android Camera预览界面拉伸问题解决

    问题现象 项目中的扫一扫界面打开以后 xff0c 扫描二维码的界面显示的二维码被拉伸 xff0c 图片如下 xff1a 问题原因 通常 xff0c 拍照预览页面的视图拉伸主要与下面两个因素有关 xff1a Surfaceview的大小Cam
  • 什么是 AOP,AOP 的作用是什么?

    分析 amp 回答 AOP的介绍 AOP全称 xff08 Aspect Oriented Programming xff09 面向切片编程的简称 AOP面向方面编程基于IoC xff0c 是对OOP的有益补充 xff1b AOP利用一种称为
  • Ubuntu图形界面卡死的解决方法

    转到字符界面 xff1a Ctrl 43 Alt 43 F1 查看进程 xff1a ps t tty7 找到Xorg进程的PID号xxx xff0c 如992 杀死进程Xorg xff1a kill xxx xff08 这里是kill 99
  • 笔记本电脑电源指示灯亮但是黑屏开不了机(或者成功开机之后发现很卡顿)的解决方法

    问题描述 本人电脑是联想拯救者Y7000P xff0c 性能如下 近期遇到一个问题 xff0c 笔记本电脑开机的之后 xff0c 突然出现卡顿 xff0c 不管是打开浏览器还是打开软件 xff0c 都要等上几秒钟 xff0c 连刷新都要等一
  • windows下的WSL开发环境配置以及相关工具、插件

    最近在自己的X1上捣鼓Django框架的编程 xff0c windows环境使用起来确实让人痛苦 xff0c 因此决定还是在Linux系统下进行Django框架的编程 xff0c 跟朋友交流了一下 xff0c 最终敲定了以下方案并把中间使用
  • 最全spring框架工作流程

    Spring执行流程 xff1a 用户发起请求到前端控制器 xff08 DispatcherServlet xff09 xff0c 该控制器会过滤出哪些请求可以访问Servlet 哪些不能访问 就是url pattern的作用 xff0c
  • python多线程爬虫教学,清晰易懂。

    首先需要知道什么是多线程 xff0c 多线程的作用 首先举个例子 xff0c 并发和并行 xff1a 并发 xff1a 并发 xff0c 在操作系统中 xff0c 是指一个时间段中有几个程序都处于已启动运行到运行完毕之间 xff0c 且这几
  • ubuntu 下ethtool安装

    1 xff0c 下载安装包 xff1a ethtool 2 6 37 tar xff0c 将其放入自己的路径下 xff0c 解压 xff1a tar xvf ethtool 2 6 37 tar 2 cd ethtool 2 6 37 执行
  • 第四章_表达式_4.9 sizeof 运算符

    4 9 sizeof 运算符 4 9 sizeof 运算符 4 9 sizeof 运算符 sizeof运算符返回一条表达式或一个类型名字所占的字节数 sizeof运算符满足右结合律 xff0c 其所得的值是一个size t类型的常量表达式
  • 初探ViewBinding

    视图访问的方式有常用的findViewById xff0c ButterKnife等多种方式 xff0c 这些方式的各方面对比如下 如上图所示 xff0c 在简明 编译安全和编译速度上都各有优势 xff0c 那么有没有一种方式可以一石 34
  • Kotlin--›Android 超轻,超好用,超简洁,超超超级RecyclerView分割线ItemDecoration封装

    需求分析 如图所示的 101 共2人 这一行 顶部有 一块白色区域 可以当做是分割线101 共2人 这一行 底部有一个很细的分割线 差不多撑满了一行人物信息 这一行 首次出现时 只有底部有分割线 而且还是 非撑满一行的效果人物信息 这一行