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

阅读: 评论:0

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

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

前言

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

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

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

效果图和代码

代码

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

效果图 网格样式

瀑布流

这个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 = SpanGroupIndex(position, spanCount)
// 最后一个item在哪一行
val lastGroupIndex = SpanGroupIndex(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) {p = mainPadding} else {outRect.left = mainPadding}
} else if (isLastGroup) {// 是最后一行要加边缘if (isVertical) {p = mainWidthoutRect.bottom = mainPadding} else {outRect.left = mainWidthoutRect.right = mainPadding}
} else {if (isVertical) {p = mainWidth} else {outRect.left = mainWidth}
}

交叉轴的间隔

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

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

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

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

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

以第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 {p = ltoutRect.bottom = rb}
}

作者:北野青阳
原文链接:

最后

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

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。

相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集


二、源码解析合集

三、开源框架合集

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

本文发布于:2024-01-31 21:50:59,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170670906431597.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23