RecyclerView详解——(二)优劣,ItemDecoration,SnapHelper

本文主要讲述RecyclerView和ListView的区别,ItemDecoration实现分割线,边距和背景,以及SnapHelper的使用。

一、RecyclerView和ListView

1. 性能和视图重用

  • ListView 使用的是 ViewHolder 模式来实现视图的重用,但需要手动配置,容易出错。
  • RecyclerView 内置了视图重用机制,且提供了 ViewHolder 作为标准。RecyclerView 更高效,尤其是在大量数据滚动时,减少了内存开销。

2. 布局管理(LayoutManager)

  • ListView 只支持垂直列表展示,没有内置的灵活布局功能。
  • RecyclerView 支持多种布局管理器 (LinearLayoutManagerGridLayoutManagerStaggeredGridLayoutManager 等),可以轻松实现垂直、水平列表、网格和瀑布流布局。此外,你可以自定义 LayoutManager 实现特殊布局。

3. 动画效果

  • ListView 没有内置动画,添加/删除数据时不会自动提供过渡动画。
  • RecyclerView 提供默认的添加、删除、移动和更改的动画效果,简化了过渡动画的实现,也可自定义动画。

4. 数据更新

  • ListView 需要调用 notifyDataSetChanged() 更新数据,不能精确更新具体位置的数据,导致性能损失。
  • RecyclerView 可以使用 notifyItemInserted()notifyItemRemoved() 等方法,只更新特定项,更加高效。同时,通过 ListAdapterDiffUtil 可实现数据的精确对比和最小范围更新。

5. 灵活性和扩展性

  • ListView 功能比较有限,适用于简单的列表显示,难以扩展或实现复杂的布局。
  • RecyclerView 提供了灵活的接口和抽象,可以轻松实现拖动、滑动删除等高级功能,适合复杂的界面需求。

7. 优缺点

  • ListView 实现简单,但缺乏灵活性,尤其在复杂应用场景中,显得力不从心。
  • RecyclerView 需要更多的代码,尤其是在实现简单的列表展示时,可能显得繁琐。对于非常简单的需求,RecyclerView 的配置和管理复杂度较高。

总结

RecyclerView 在性能和扩展性方面明显优于 ListView,适合现代应用的需求。对于简单的列表或无需频繁数据更新的场景,ListView 也可以考虑,但通常推荐使用 RecyclerView 来替代 ListView 以获得更好的用户体验。

二、RecyclerView ItemDecoration

1. 实现分割线

使用 DividerItemDecoration 类为 RecyclerView 添加分割线:

val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)// 使用系统提供的 DividerItemDecoration
val dividerItemDecoration = DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
recyclerView.addItemDecoration(dividerItemDecoration)

实现效果:

如果想要自定义分割线,可以继承 RecyclerView.ItemDecoration 并重写 onDraw() 方法:

class CustomDividerDecoration(private val dividerHeight: Int, private val dividerColor: Int) : RecyclerView.ItemDecoration() {private val paint = Paint()init {paint.color = dividerColorpaint.style = Paint.Style.FILL}override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {val left = parent.paddingLeftval right = parent.width - parent.paddingRightfor (i in 0 until parent.childCount - 1) {val child = parent.getChildAt(i)val params = child.layoutParams as RecyclerView.LayoutParamsval top = child.bottom + params.bottomMarginval bottom = top + dividerHeightcanvas.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), paint)}}
}

使用:

val customDivider = CustomDividerDecoration(10, Color.GRAY)
recyclerView.addItemDecoration(customDivider)

效果:

tips:

DividerItemDecoration 默认会在每个 RecyclerView 子项的底部绘制分割线,垂直布局的 RecyclerView 会在子项的下方画分割线,而水平布局的 RecyclerView 会在子项的右侧画分割线。

如果你需要自定义分割线的位置,比如只在顶部、左右侧或者每个子项的周围,都可以通过自定义 ItemDecoration 并手动绘制来实现。

2. 实现边距 (Margin)

创建一个 ItemDecoration 子类为每个子项设置边距:

class MarginItemDecoration(private val space: Int) : RecyclerView.ItemDecoration() {override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {outRect.left = spaceoutRect.right = spaceoutRect.top = spaceoutRect.bottom = space}
}

 使用:

val marginDecoration = MarginItemDecoration(16) // 设置边距大小
recyclerView.addItemDecoration(marginDecoration)

实现效果

tips:为了方便观看,我给每个子项增加了一个浅黄色的背景, 可以看到,他的上下左右都有16像素的间距,如果你的上下间距为6px,分割线恰好为12px,那么间距的高度就刚好和分割线一致,就不会看到中间的白色间隔了。

3. 实现背景

如果需要为每个子项添加背景色,可以创建一个自定义 ItemDecoration

class BackgroundItemDecoration(private val backgroundColor: Int) : RecyclerView.ItemDecoration() {private val paint = Paint()init {paint.color = backgroundColorpaint.style = Paint.Style.FILL}override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {for (i in 0 until parent.childCount) {val child = parent.getChildAt(i)val left = child.left.toFloat()val top = child.top.toFloat()val right = child.right.toFloat()val bottom = child.bottom.toFloat()canvas.drawRect(left, top, right, bottom, paint)}}
}

使用:

val backgroundDecoration = BackgroundItemDecoration(Color.RED)
recyclerView.addItemDecoration(backgroundDecoration)

效果:

因为我给item设置了浅黄色背景,所以可以看到我的列表,只有header因为没有设置背景,所以才是红色的。

如果我给xml设置的背景色有透明度,或者直接不设置背景,那么就会生效。

效果:item背景色设置为有透明度的颜色  android:background="#5AFFFFCC"

可以看到,背景生效了,header的背景是纯红色,下面数据列表item的背景则是橙红色。

4. 总结

因为分开写例子会更清楚些,我就分开实现的,实际需求肯定比这个繁琐,混合搭配更合适

  • 分割线:可以使用 DividerItemDecoration 或自定义的 ItemDecoration
  • 边距:通过自定义 ItemDecorationgetItemOffsets() 方法来设置 Rect 的间距。
  • 背景:使用 onDraw() 在每个子项的区域绘制背景色。

三、RecyclerView SnapHelper

SnapHelper是一个辅助类,用于帮助 RecyclerView 在滚动停止时将某个 item 精确地对齐到 RecyclerView 的特定位置,例如对齐到 RecyclerView 的开头、中间或末尾。使用 SnapHelper 可以实现类似于分页滚动、对齐中心点的效果,适合用于Banner轮播图、分页卡片等效果。

Android 提供了两种内置的 SnapHelper 子类:

  1. LinearSnapHelper:让 RecyclerView 在滚动停止时将最接近中心的 item 对齐到 RecyclerView 的开头(或者视图中心)。
  2. PagerSnapHelper:实现类似 ViewPager 的分页滚动效果,让每次滚动只显示一个 item,自动将其对齐到开始位置。
1. 使用 LinearSnapHelper

例如,当我有一个横向的画廊的时候,使用viewpager,一次划一下展示下一张,不可以一下划多页,那么如果是一个列表去实现滑动,又很容易划到一半,两张图片都占据在屏幕中,会很丑,之前做过类似需求,去算item在屏幕中展示的偏移量让item滚动到正确位置,不稳定,哎,当时也没想到用SnapHelper

LinearSnapHelper 适用于横向或纵向的 RecyclerView,用于对齐单个 item 到视图的中心。

val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recyclerView.adapter = YourAdapter()// 创建并附加 LinearSnapHelper
val snapHelper = LinearSnapHelper()
snapHelper.attachToRecyclerView(recyclerView)

实现效果:

可以看到,当我滑动到一定位置时,他就自动划到上一项,且上一项自己居中了。 如果手指快速滑动,则会一次性滚动多个Item。

当然,因为我上面的图片设置得有点大,所以一次就看到一张图,如果Item宽度小一点,则是这样的效果:

是不是和Banner展示得很像,且item始终会居中

 

2. 使用 PagerSnapHelper

PagerSnapHelper 的效果类似于 ViewPager,每次滚动只显示一个 item,非常适合类似分页效果的需求。因为之前有个画廊的需求,使用Viewpager过于繁琐,后面直接使用RecyclerView搭配PagerSnapHelper,很轻松就实现了。

代码:

val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recyclerView.adapter = YourAdapter()// 创建并附加 PagerSnapHelper
val pagerSnapHelper = PagerSnapHelper()
pagerSnapHelper.attachToRecyclerView(recyclerView)

PagerSnapHelper 将自动分页滚动。这个效果很像 ViewPager 但不需要单独的 ViewPager 控件。一次滑动只能滚动一个Item哦。

3. 监听 Snap 事件

为了实现更高级的需求,可以监听 Snap 事件。例如,当某个 item 滚动对齐时,可以触发回调。可以利用 RecyclerView.OnScrollListenerSnapHelper 来检测当前对齐的 item 索引:

recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {super.onScrollStateChanged(recyclerView, newState)if (newState == RecyclerView.SCROLL_STATE_IDLE) {val snapView = snapHelper.findSnapView(recyclerView.layoutManager)val position = recyclerView.layoutManager?.getPosition(snapView ?: return)position?.let {// Do something with the snapped item positionLog.d("SnapHelper", "Snapped to position: $position")}}}
})

在这个监听器中,当滚动停止并对齐某个 item 时,会输出该 item 的位置。这在更新 UI 或加载相应的数据时非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/13287.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

[运维][Nginx]Nginx学习(2/5)-Nginx高级

Nginx服务器基础配置实例 前面我们已经对Nginx服务器默认配置文件的结构和涉及的基本指令做了详细的阐述。通过这些指令的合理配置&#xff0c;我们就可以让一台Nginx服务器正常工作&#xff0c;并且提供基本的web服务器功能。 接下来我们将通过一个比较完整和最简单的基础配…

动态规划习题其四【力扣】【算法学习day.26】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…

candence : 原理图如何导出原理库?

原理图如何导出原理库&#xff1f; 1、打开要需要导出原理图库的工程文件&#xff0c;新建一个原理图库&#xff1a; 2、copy 需要导出的原理图的库文件 3、粘贴到 刚刚新建的原理图库文件中即可 完成 可以一个一个复制&#xff0c;也可以多可一起复制。

二叉树的遍历

普通二叉树的遍历 前序遍历:根 左子树 右子树 中序遍历:左子树 根 右子树 后序遍历:左子树 右子树 根 一颗普通二叉树的实现 #include<stdlib.h> //树的定义 typedef int BTDataType; typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left;s…

WebStorm 如何调试 Vue 项目

前言 在日常开发和各种教程中&#xff0c;最常见的 debug 方式就是在代码中插入 console.log 语句&#xff0c;然后在 Chrome 控制台中查看日志。显而易见&#xff0c;插入console.log 的效率不高&#xff0c;那是否有更高效的 debug 方式呢&#xff1f;断点调试允许开发者在代…

timedatectl status显示系统时间相关信息

timedatectl status命令用于显示当前系统的时间和日期相关信息。 下面是每行含义&#xff1a; Local time: 当前系统的本地时间Universal time: 当前系统的协调世界时&#xff08;UTC&#xff09;RTC time: 硬件时钟&#xff08;Real Time Clock&#xff09;的时间Time zone:…

【网页设计】HTML5 和 CSS3 提高

目标 能够说出 3~5 个 HTML5 新增布局和表单标签能够说出 CSS3 的新增特性有哪些 1. HTML5 的新特性 注&#xff1a;该部分所有内容可参考菜鸟教程菜鸟教程 - 学的不仅是技术&#xff0c;更是梦想&#xff01; (runoob.com) HTML5 的新增特性主要是针对于以前的不足&#xf…

09C++结构体

/*结构体属于用户自定义的数据类型&#xff0c; 允许用户存储不同的数据类型, 语法:struct 结构体名{结构体成员列表} ;*/ //struct 结构体名 变量名 #include <iostream> #include <string> using namespace std; struct student { string name; int age;int s…

软件测试之白盒测试(超详细总结)

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 白盒测试 白盒测试&#xff08;White Box Testing&#xff09;又称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试。白盒测试只测试软件产品的内部结…

【入门篇】数字统计——多语言版

题目跳转&#xff1a;数字统计 题目解析&#xff1a; 这道题目要求统计在给定范围 [L, R] 内所有整数中数字 2 出现的次数。例如&#xff0c;在范围 [2, 22] 中&#xff0c;数字 2 分别在数 2、12、20、21、22 中出现的次数&#xff0c;最终出现了6次。 题目的输入为两个正…

C++初阶——list

一、什么是list list是一个可以在序列的任意位置进行插入和删除的容器&#xff0c;并且可以进行双向迭代。list的底层是一个双向链表&#xff0c;双向链表可以将它们包含的每个元素存储在不同且不相关的存储位置。通过将每个元素与前一个元素的链接和后一个元素的链接关联起来&…

FlinkSql读取kafka数据流的方法(scala)

我的scala版本为2.12 <scala.binary.version>2.12</scala.binary.version> 我的Flink版本为1.13.6 <flink.version>1.13.6</flink.version> FlinkSql读取kafka数据流需要如下依赖&#xff1a; <dependency><groupId>org.apache.flink&…

力扣 LeetCode 19. 删除链表的倒数第N个结点(Day2:链表)

解题思路&#xff1a; 快慢指针 class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {ListNode dummy new ListNode(-1);dummy.next head;ListNode fast dummy;ListNode slow dummy;for (int i 0; i < n; i) {fast fast.next;}while (fast.ne…

提升法律文书处理效率的秘密武器:开源文档比对工具解析

本篇文章介绍了一款针对律师行业的免费开源文档比对工具&#xff0c;旨在解决法律文档的多版本比对难题。通过逐字、逐句精确比对、语义分析、批量处理等核心功能&#xff0c;该工具可高效识别文本差异&#xff0c;提升文书审查效率并降低错误风险。它支持多种文件格式&#xf…

linux命令详解,openssl+历史命令详解

openssl openssl是一个开源的加密工具包&#xff0c;提供了各种加密、解密、签名、验证等功能 openssl passwd -1 123password表示这个命令用于处理密码相关的操作&#xff0c;-1参数指定使用MD5加密算法对密码“123”进行加密处理。MD5是一种常用的哈希算法&#xff0c;它将…

轻松理解操作系统 - Linux的虚拟文件系统是如何简化我们的使用的?

在前面几期&#xff0c;我们不仅了解了 Linux文件系统 是如何在硬盘等储存介质上保存文件的&#xff1a; 什么是软硬链接 文件的“身份证” - inode 真正储存文件的地方 - 数据块 文件系统的心脏 - 超级块 以及了解了 Linux系统 中具体都有一些什么文件&#xff1a; Linu…

LeetCode【0019】删除链表的倒数第N个结点

本文目录 1 中文题目2 求解方法&#xff1a;虚拟头节点和快慢指针2.1 方法思路2.2 Python代码2.3 复杂度分析 3 题目总结 1 中文题目 给定一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例&#xff1a; 链表如上&#xff1a; 输入&a…

【JavaSE】多线程案例---阻塞队列

1. 阻塞队列 阻塞队列是一种特殊的队列&#xff0c;也遵守 " 先进先出 " 的原则。 阻塞队列是一种线程安全的数据结构&#xff0c;并且具有以下特性&#xff1a; 1. 当队列为满时&#xff0c;继续进行入队列操作就会阻塞&#xff0c;直到有其他线程从队列中取走元素…

SQL练习(2)

题源&#xff1a;牛客官网 选择题 假设创建新用户nkw&#xff0c;现在想对于任何IP的连接&#xff0c;仅拥有user数据库里面的select和insert权限&#xff0c;则列表语句中能够实现这一要求的语句是&#xff08;&#xff09; A grant select ,insert on *.* to nkw% B grant…

Hyper-v中ubuntu与windows文件共享

Hyper-v中ubuntu与windows文件共享 前言相关链接第一步--第一个链接第二步--第二个链接测试与验证 前言 关于Hyper-V的共享我搞了好久&#xff0c;网上的很多教程太过冗余&#xff0c;我直接采用最简单的办法吧 相关链接 Hyper-V中Ubuntu 同windows系统共享文件夹-百度经验 …