写一个万用RecyclerView分隔线,支持linear grid staggered

2023-12-29 22:30

本文主要是介绍写一个万用RecyclerView分隔线,支持linear grid staggered,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

2023已过半,才发现我已经大半年没写博客了,痛定思痛决定水一篇。

不知道大家平时干活的时候有没有被RecyclerView列表的分隔线困扰过,app里一般都会有各种各样的列表,横的竖的、网格、瀑布流样式的,每次要给列表设分隔线时都要自己写一个特化的ItemDecoration,既麻烦又难以复用,那能不能写一个适用大多数场景的ItemDecoration来减轻这类负担呢?

别急,本篇文章就给大家带来一个我自用的通用ItemDecoration,支持linear grid staggered LayoutManager,支持横竖向、跨列等情况;支持边缘、横纵向分隔线不同宽度,使用也非常简单。

效果图和代码

代码

单个类可以直接使用,仓库包含demo

效果图 网格样式

20230621_173920.gif

瀑布流

20230621_174043.gif

这个ItemDecoration暂时没有实现分隔线上色,因为我觉得这种场景其实很少就把相关代码删掉了,要加的话建议通过继承实现。

实现和注意点

首先,由于要支持横竖向,所以定义两个轴,主轴代表可滑动的那个轴,交叉轴代表另一个轴,这样无论是横向还是竖向都能保持语义一致

// 主轴方向分割线宽度
protected var mainWidth = 0// 交叉轴方向分割线宽度
protected var crossWidth = 0// 边缘宽度
protected var mainPadding = 0
protected var crossPadding = 0

主轴的间隔

主轴的分隔线很简单,第一行的item和最后一行的item设置边缘间隔,其他每个item在主轴同一方向上设置分隔线间隔,关键点在于首行和末行的判断。

LinearLayoutManager情况下最简单,判断position是首个或者最后一个就ok了,但是GridLayoutManager和StaggeredGridLayoutManager都存在跨列问题。比如说列表有5列,但是第一个item就占满了整行,那么本该在第一行的2-5个item实际上就不在第一行了;末行判断同理。

GridLayoutManager通过它的SpanSizeLookup来判断,groupIndex0在首行,groupIndexlastGroupIndex在最后一行

// 当前item在哪一行
val groupIndex = manager.spanSizeLookup.getSpanGroupIndex(position, spanCount)
// 最后一个item在哪一行
val lastGroupIndex = manager.spanSizeLookup.getSpanGroupIndex(size - 1, spanCount)

StaggeredGridLayoutManager相对麻烦一些,看下面的注释,spanIndex代表当前item在本行内的下标

val lp = view.layoutParams
if (lp is StaggeredGridLayoutManager.LayoutParams) {val spanCount = manager.spanCount// 前面没有跨列item时当前item的期望下标val exceptSpanIndex = position % spanCount// 真实的item下标val spanIndex = lp.spanIndex// position原属于第一行并且此item之前没有跨列的情况,当前item才属于第一行val isFirstGroup = position < spanCount && exceptSpanIndex == spanIndexvar isLastGroup = falseif (size - position <= spanCount) {// position原属于最后一行val lastItemView = manager.findViewByPosition(size - 1)if (lastItemView != null) {val lastLp = lastItemView.layoutParamsif (lastLp is StaggeredGridLayoutManager.LayoutParams) {// 列表最后一个item和当前item的spanIndex差等于position之差说明它们之间没有跨列的情况,当前item属于最后一行if (lastLp.spanIndex - spanIndex == size - 1 - position) {isLastGroup = true}}}}
}

接下来就很简单了,设置主轴上的间隔

if (isFirstGroup) {// 是第一行if (isVertical) {outRect.top = mainPadding} else {outRect.left = mainPadding}
} else if (isLastGroup) {// 是最后一行要加边缘if (isVertical) {outRect.top = mainWidthoutRect.bottom = mainPadding} else {outRect.left = mainWidthoutRect.right = mainPadding}
} else {if (isVertical) {outRect.top = mainWidth} else {outRect.left = mainWidth}
}

交叉轴的间隔

交叉轴的分隔线最简单的是LinearLayoutManager,由于不存在多列直接设置为边缘间隔就可以了

if (isVertical) {outRect.left = crossPaddingoutRect.right = crossPadding
} else {outRect.top = crossPaddingoutRect.bottom = crossPadding
}

GridLayoutManager和StaggeredGridLayoutManager的交叉轴分隔线计算方法是一样的,可以统一处理,需要遵循的规则有两个

  1. 每列占用的左右间隔之和相等
  2. 每个item占用的右间隔和它相邻item占用的左间隔之和等于给定的间隔宽度

以下图为例,列表共4列,边缘间隔是15,item间隔是10,第二个item跨两列,每列应该占用的空间为15。

image.png

以第3个item为例,如何计算出它的左间隔(第三个绿色部分的宽度)和右间隔(第二个红色部分的宽度,公式如下

左间隔:到当前item的左边为止的总间隔(crossWidth * spanIndex + crossPadding)减去 到上一个item为止需要使用的总间隔(spanUsedWidth * spanIndex),这个例子中这两个值相等

同理右间隔:到当前item为止需要使用的总间隔(spanUsedWidth * (spanIndex + spanSize)) 减去 到当前item右边为止的总间隔(crossWidth * (spanIndex + spanSize - 1) + crossPadding);当然也可以用 当前item需要使用的总间隔( spanUsedWidth * spanSize) - 当前item已经使用的总间隔( crossWidth * (spanSize - 1) + lt)

这样通过归纳只使用两行代码就统合了所有情况

/*** 交叉轴间隔* [spanIndex] 当前item的以第几列开始* [spanSize] 当前item占用的列数*/
private fun getItemCrossOffsets(outRect: Rect, isVertical: Boolean, spanCount: Int, spanIndex: Int, spanSize: Int) {// 每列占用的间隔val spanUsedWidth = (crossPadding * 2 + crossWidth * (spanCount - 1)) / spanCount// 到当前item的左边为止的总间隔 - 到上一个item为止需要使用的总间隔val lt = crossWidth * spanIndex + crossPadding - spanUsedWidth * spanIndex// 到当前item为止需要使用的总间隔 - 到当前item右边为止的总间隔
//        val rb = spanUsedWidth * (spanIndex + spanSize) - crossWidth * (spanIndex + spanSize - 1) - crossPadding// 当前item需要使用的总间隔 - 当前item已经使用的总间隔val rb = spanUsedWidth * spanSize - crossWidth * (spanSize - 1) - ltif (isVertical) {outRect.left = ltoutRect.right = rb} else {outRect.top = ltoutRect.bottom = rb}
}

作者:北野青阳
原文链接:https://juejin.cn/post/7248811984749527101

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述

欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

这篇关于写一个万用RecyclerView分隔线,支持linear grid staggered的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/550909

相关文章

理解分类器(linear)为什么可以做语义方向的指导?(解纠缠)

Attribute Manipulation(属性编辑)、disentanglement(解纠缠)常用的两种做法:线性探针和PCA_disentanglement和alignment-CSDN博客 在解纠缠的过程中,有一种非常简单的方法来引导G向某个方向进行生成,然后我们通过向不同的方向进行行走,那么就会得到这个属性上的图像。那么你利用多个方向进行生成,便得到了各种方向的图像,每个方向对应了很多

Golang支持平滑升级的HTTP服务

前段时间用Golang在做一个HTTP的接口,因编译型语言的特性,修改了代码需要重新编译可执行文件,关闭正在运行的老程序,并启动新程序。对于访问量较大的面向用户的产品,关闭、重启的过程中势必会出现无法访问的情况,从而影响用户体验。 使用Golang的系统包开发HTTP服务,是无法支持平滑升级(优雅重启)的,本文将探讨如何解决该问题。 一、平滑升级(优雅重启)的一般思路 一般情况下,要实现平滑

sqlite不支持中文排序,采用java排序

方式一 不支持含有重复字段进行排序 /*** sqlite不支持中文排序,改用java排序* 根据指定的对象属性字段,排序对象集合,顺序* @param list* @param field* @return*/public static List sortListByField(List<?> list,String field){List temp = new ArrayList(

一款支持同一个屏幕界面同时播放多个视频的视频播放软件

GridPlayer 是一款基于 VLC 的免费开源跨平台多视频同步播放工具,支持在一块屏幕上同时播放多个视频。其主要功能包括: 多视频播放:用户可以在一个窗口中同时播放任意数量的视频,数量仅受硬件性能限制。支持多种格式和流媒体:GridPlayer 支持所有由 VLC 支持的视频格式以及流媒体 URL(如 m3u8 链接)。自定义网格布局:用户可以配置播放器的网格布局,以适应不同的观看需求。硬

Science Robotics 首尔国立大学研究团队推出BBEX外骨骼,实现多维力量支持!

重复性举起物体可能会对脊柱和背部肌肉造成损伤,由此引发的腰椎损伤是工业环境等工作场所中一个普遍且令人关注的问题。为了减轻这类伤害,有研究人员已经研发出在举起任务中为工人提供辅助的背部支撑装置。然而,现有的这类装置通常无法在非对称性的举重过程中提供多维度的力量支持。此外,针对整个人体脊柱的设备安全性验证也一直是一个缺失的环节。 据探索前沿科技边界,传递前沿科技成果的X-robot投稿,来自首尔国立

LibSVM学习(六)——easy.py和grid.py的使用

我们在“LibSVM学习(一)”中,讲到libSVM有一个tools文件夹,里面包含有四个python文件,是用来对参数优选的。其中,常用到的是easy.py和grid.py两个文件。其实,网上也有相应的说明,但很不系统,下面结合本人的经验,对使用方法做个说明。        这两个文件都要用python(可以在http://www.python.org上下载到,需要安装)和绘图工具gnup

超级 密码加密 解密 源码,支持表情,符号,数字,字母,加密

超级 密码加密 解密 源码,支持表情,符号,数字,字母,加密 可以将表情,动物,水果,表情,手势,猫语,兽语,狗语,爱语,符号,数字,字母,加密和解密 可以将文字、字母、数字、代码、标点符号等内容转换成新的文字形式,通过简单的文字以不同的排列顺序来表达不同的内容 源码截图: https://www.httple.net/152649.html

QtC++截图支持窗口获取

介绍 在截图工具中你会发现,接触到窗口后会自动圈出目标窗口,个别强大一点的还能进行元素识别可以自动圈出元素,那么今天简单分析一下QTc++如何获取窗口并圈出当前鼠标下的窗口。 介绍1.如何获取所有窗口2.比较函数3.实现窗口判断 结尾 1.如何获取所有窗口 1.我们需要调用windows接口EnumWindowsProc回调函数来获取所有顶级窗口,需要包含windows.

Nacos Config 配置中心支持配置共享

文章目录 一、什么是配置中心二、Nacos Config2.1 Nacos Config 工作原理 (★)2.2 Nacos Config 的使用2.3 动态刷新2.4 配置共享2.4.1 同一个微服务的不同环境之间共享配置2.4.2 不同微服务中间共享配置 一、什么是配置中心 微服务架构下关于配置文件的存在以下问题: 配置文件相对分散。在一个微服务架构下,配置文件会随

spring笔记 多线程的支持

spring的工作机制 136  属性编辑器 140 spring事件的体系结构 168 Bean间的关系 109 继承 依赖 引用     Bean的继承          1 为了简化初始化的属性注入;          2 子Bean和父Bean相同的属性值,使用子Bean的     Bean的依赖 Srping控制相互依赖的Bean之间,属性注入的顺序,防止出错  depend-on