引入依赖库:

implementation 'androidx.recyclerview:recyclerview:1.1.0'

一、ItemDecoration概念

给recyclerView的item设置分割线的。

1、itemDecoration允许应用给具体的View添加具体的图画或者layout的偏移,对于绘制View之间的分割线,视觉分组边界等等是非常有用的。

2、当我们调用addItemDecoration()方法添加itemDecoration的时候,RecyclerView就会调用该类的onDraw方法去绘制分割线,也就是说,分割线是绘制出来的。

3、RecyclerView.ItemDocoration,该类为抽象类,官方目前只提供了一个实现类DivideItemDecoration。

二、ItemDocoration的源码,里面提供了三个废弃的方法和三个可用的方法(onDraw、onDrawOver、getItemOffsets)

public abstract static class ItemDecoration {/*** Draw any appropriate decorations into the Canvas supplied to the RecyclerView.* Any content drawn by this method will be drawn before the item views are drawn,* and will thus appear underneath the views.** @param c Canvas to draw into* @param parent RecyclerView this ItemDecoration is drawing into* @param state The current state of RecyclerView*/public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull State state) {onDraw(c, parent);}/*** @deprecated* Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)}*/@Deprecatedpublic void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent) {}/*** Draw any appropriate decorations into the Canvas supplied to the RecyclerView.* Any content drawn by this method will be drawn after the item views are drawn* and will thus appear over the views.** @param c Canvas to draw into* @param parent RecyclerView this ItemDecoration is drawing into* @param state The current state of RecyclerView.*/public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent,@NonNull State state) {onDrawOver(c, parent);}/*** @deprecated* Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)}*/@Deprecatedpublic void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent) {}/*** @deprecated* Use {@link #getItemOffsets(Rect, View, RecyclerView, State)}*/@Deprecatedpublic void getItemOffsets(@NonNull Rect outRect, int itemPosition,@NonNull RecyclerView parent) {outRect.set(0, 0, 0, 0);}/*** Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies* the number of pixels that the item view should be inset by, similar to padding or margin.* The default implementation sets the bounds of outRect to 0 and returns.** <p>* If this ItemDecoration does not affect the positioning of item views, it should set* all four fields of <code>outRect</code> (left, top, right, bottom) to zero* before returning.** <p>* If you need to access Adapter for additional data, you can call* {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the* View.** @param outRect Rect to receive the output.* @param view    The child view to decorate* @param parent  RecyclerView this ItemDecoration is decorating* @param state   The current state of RecyclerView.*/public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,@NonNull RecyclerView parent, @NonNull State state) {getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),parent);}}

有6个方法,其中三个有注解@Deprecated表示不能用的,其中OnDraw和onDrawOver代表的是绘制,getItemOffsets设置item的偏移量,通过outRect.set(0, 0, 0, 0);来设置的。

1、getItemOffsets方法

  • getItemOffsets方法,主要就是给itemView设置偏移量,比如RecyclerView的设置LinearLayoutManger,使用Vertical垂直方向,那上下item之间的分隔线的空间,就可以在这设置。
  • outRect.set(0, 5, 0, 0),就代表top方向偏移5像素点,然后就预留出了5像素点高度的空间,给你绘制分隔线,而不会影响itemView(即垂直的时候设置了上下不会影响item高度,设置了左右会影响item宽度)。
  • 看注释,设置偏移量要在后面,就是super要么不写,要么写在前面,看源码super把全部设置为0。

2、onDraw方法

这个方法绘制的东西,会在RecyclerView的item绘制之前绘制,所以onDraw绘制的东西可能会被压在item的下面,如果设置了getItemOffsets间距,绘制的距离在这个间距内就不会被遮住,如果onDraw绘制的东西的边距超过了Offsets设置的间距,就会被遮住。

3、onDrawOver方法

onDrawOver跟onDraw刚好相反,他是在RecyclerView绘制之后绘制,会盖在RecyclerView上面(如果设置了getItemOffsets间距,onDrawOver绘制的距离在这个间距内就不会遮住itemView,如果onDrawOver绘制的东西的边距超过了Offsets设置的间距,就会遮住ItemView。)

二、RecyclerView利用ItemDecoration实现吸顶效果

1.继承RecyclerView.ItemDecoration,重写getItemOffsets方法

@Overridepublic void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {super.getItemOffsets(outRect, view, parent, state);if (parent.getAdapter() instanceof StarAdapter) {StarAdapter adapter = (StarAdapter) parent.getAdapter();//RecyclerView的LayoutParams,是有viewHolder的,所以可以通过View 获取LayoutParams,再拿到ViewHolder//获取当前view对应的positionint childLayoutPosition = parent.getChildLayoutPosition(view);//判断是否是头部boolean isGroupHeader = adapter.isGroupHeader(childLayoutPosition);if (isGroupHeader) {//如果当前item是头部,则预留更大的空间outRect.set(0, groupHeaderHeight, 0, 0);} else {//不是头部隔开:1像素outRect.set(0, 1, 0, 0);}}}

如果此时给RecyclerView设置个背景,就可以看到间隔处有颜色了。记住这是recyclerView的背景,并不是我们画的分割线,我还没重写onDraw和onDrawOver呢。(分割线有清晰和不清晰应该是模拟器的问题,我在真机上都是清晰的)

2.重写onDraw方法,开始在上一步item之间分割出来的间距进行绘制。把画笔的颜色改成BLUE,即分割线绘制成蓝色,并绘制相关字符串。

@Overridepublic void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {super.onDraw(c, parent, state);if (parent.getAdapter() instanceof StarAdapter) {StarAdapter adapter = (StarAdapter) parent.getAdapter();//当前屏幕的item个数int childCount = parent.getChildCount();//recyclerView的左边padding值作为绘制分割线的左int left = parent.getPaddingLeft();//分割线的右边int right = parent.getWidth() - parent.getPaddingRight();for (int i = 0; i < childCount; i++) {//获取对应i的ViewView childAt = parent.getChildAt(i);int childLayoutPosition = parent.getChildLayoutPosition(childAt);boolean isGroupHeader = adapter.isGroupHeader(childLayoutPosition);//是否为头部if (isGroupHeader && childAt.getTop() - groupHeaderHeight - parent.getPaddingTop() >= 0) {c.drawRect(left, childAt.getTop() - groupHeaderHeight, right, childAt.getTop(), headerPaint);String groupName = adapter.getGroupName(childLayoutPosition);Log.i("BK", groupName + " " + childAt.getTop());textPaint.getTextBounds(groupName, 0, groupName.length(), textRect);c.drawText(groupName, left + 20, childAt.getTop() - groupHeaderHeight / 2+ textRect.height() / 2, textPaint);} else if (childAt.getTop() - groupHeaderHeight - parent.getPaddingTop() >= 0){//分割线c.drawRect(left, childAt.getTop() - 1, right, childAt.getTop(), headerPaint);}}}}

3.重写OnDrawOver方法,实现吸顶的效果:因为吸顶效果是覆盖在itemView上的,所以只能用个这个方法来实现。

@Overridepublic void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {super.onDrawOver(c, parent, state);if (parent.getAdapter() instanceof StarAdapter) {StarAdapter adapter = (StarAdapter) parent.getAdapter();//屏幕可视的第一个itemView的位置int firstVisibleItemPosition = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition();//获取position对应的viewView itemView = parent.findViewHolderForAdapterPosition(firstVisibleItemPosition).itemView;int left = parent.getPaddingLeft();int right = parent.getWidth() - parent.getPaddingRight();int top = parent.getPaddingTop();//当屏幕可视范围内,第二个itemView是下一组的头部的时候boolean isGroupHeader = adapter.isGroupHeader(firstVisibleItemPosition + 1);if (isGroupHeader) {//这种情况就要将上一个吸顶的慢慢往上顶的效果Log.i("BK", "onDrawOver1: " + firstVisibleItemPosition);//bottom会随着上滑越来越小int bottom = Math.min(groupHeaderHeight, itemView.getBottom()-parent.getPaddingTop());c.drawRect(left, top, right, top + bottom, headerPaint);String groupName = adapter.getGroupName(firstVisibleItemPosition);textPaint.getTextBounds(groupName, 0, groupName.length(), textRect);c.drawText(groupName, left + 20, top + bottom - groupHeaderHeight / 2+ textRect.height() / 2, textPaint);} else {//固定在顶部的效果Log.i("BK", "onDrawOver2: " + firstVisibleItemPosition);c.drawRect(left, top, right, top + groupHeaderHeight, headerPaint);String groupName = adapter.getGroupName(firstVisibleItemPosition);textPaint.getTextBounds(groupName, 0, groupName.length(), textRect);c.drawText(groupName, left + 20, top + groupHeaderHeight / 2+ textRect.height() / 2, textPaint);}}}

每行代码的注释也清楚了,可以自己运行体会体会。其实在getItemOffsets把控件预留出来了,剩下的分割线绘制就和自定义View的绘制差不多了。

Github完整项目代码

RecyclerView实现吸顶效果---ItemDecoration相关推荐

  1. Android RecyclerView 吸顶效果(一)

    实现效果: 实现方案介绍 recyclerView实现吸顶效果有2种方案: 方案1: 通过ItemDecoration 并重写对应的getItemOffsets().onDraw().onDrawOv ...

  2. 最贴近京东首页体验的嵌套滑动吸顶效果

    吸顶效果是各家 App 或多或少都会用的一个交互,这种交互也常见于 PC.H5,可以说是一种通用性很强的前端交互体验,相比较来说京东首页的嵌套滑动吸顶效果是各个类似效果中体验比较好的一个,因为在嵌套布 ...

  3. android滑动自动吸顶效果,安卓当下最流行的吸顶效果的实现(上)

    原标题:安卓当下最流行的吸顶效果的实现(上) 开始逐渐领略到ItemDecoration的美~ 今天让我 使用 ItemDecoration 来完成 可推动的悬浮导航栏的效果,最终实现的效果如下图: ...

  4. Android - 吸顶效果 布局篇

    调研了一下微博和豆瓣等大体量的APP,发现内容详情页的评论吸顶效果非常常见. 以截图自豆瓣的效果为例,当上划至内容部分消失时,滑动中的回复条会置顶,并保持在位置不动. 笔者通过实践,记录下目前发现的最 ...

  5. 仿微博发现页吸顶效果

    整个首页布局采用 CoordinatorLayout 布局,实现正常的吸顶效果.然后监听 AppBarLayout 的展开与折叠.我直接上代码吧. 首页外部布局: <androidx.coord ...

  6. 30秒实现Vue吸顶效果

    酱酱,好久不见鸭! 前言:吸顶效果图: 1.滚动前: image.png 2.滚动中: image.png 3.滚动超过后: image.png 直观效果可参pc端微博左侧的信息栏 第一步:html ...

  7. vue音乐项目歌手页面滚动、吸顶效果

    总结singer页面: 1.api中去获取 ['热',A-Z] 以及根据['热',A-Z]获取的所有歌手的数据 2.渲染数据 2.1 渲染左边 字母title ['热',A-Z] + 该字母开头的歌手 ...

  8. 微信小程序中实现吸顶效果(流畅、不卡顿)

    欢迎访问我的 个人博客 最开始的时候,在小程序中实现吸顶效果,开发工具看起来还挺好的,但是在真机上就会有问题了. 原因是我不停的去 setData 会导致操作反馈延迟严重,无法及时将操作处理结果及时传 ...

  9. vue中怎么实现吸顶效果

    在 web 应用中,我们经常需要让页面中的一个或多个元素在页面滚动时保持固定位置.这种效果通常被称为吸顶效果,因为它使元素像粘在页面顶部一样固定不动. 在 Vue 中,实现吸顶效果有不同的方法.本文将 ...

  10. Flutter吸顶效果

    前言: 关于吸顶效果,在Flutter当中,已经提供了这么一个控件,但是由于太复杂,所以网上的资料有些少,本文章主要利用Flutter自带的这种吸顶动画控件,配合着动画完成的一个用户中心的页面. im ...

最新文章

  1. Asp.net SignalR 应用并实现群聊功能 开源代码
  2. Delphi动态事件
  3. [python爬虫] Selenium爬取内容并存储至MySQL数据库
  4. Java8 Lambda总结
  5. android 记录路线轨迹_基于百度地图SDK记录运动轨迹
  6. ffmpeg libx264_nginx+ffmpeg搭建流媒体服务器(直播流)
  7. 哈希表 Hashtable c# 1613537346
  8. visual c语言编译运行结果,Visual Studio 2015编译运行C语言文件问题小结
  9. java----Servlet的生命周期
  10. 深度学习实践指南(五)—— 求解异或问题
  11. 【第105期】游戏策划:应聘简历的附件那些事
  12. 轻量引入 好看字体 font-spider 字蛛
  13. 24节气—霜降文案、海报 , 秋将去,降初霜。
  14. 【verbs】ibv_create_cq()
  15. tokenize java,Java split string - Java tokenize string examples - 入门小站-rumenz.com
  16. 技术债治理的三条原则
  17. Javascript 实现一个分钟秒钟倒计时器
  18. 依赖倒转原则和里氏代换原则详解
  19. 微信小程序入门(登录页面)
  20. uni-app 二维码转base64 分享

热门文章

  1. 图像校色 白平衡调整
  2. linux raid 监控,如何使用CentOS 6监控Dell PERC H710 Raid控制器背后的硬盘状态?
  3. MMPB/GBSA结合自由能计算以残基贡献度分析
  4. GRUB和LILO的区别
  5. ISA TEST黑客过关小游戏第二关解密
  6. OEM、ODM、OBM分别是什么?
  7. 【小组成员个人简介】Fantasy
  8. 目标检测跟踪算法综述
  9. IE浏览器请求打开谷歌浏览器
  10. 网站如何统计访问人数?51LA如何安装使用?