RecyclerView 自定义ItemDecoration从入门到实现吸顶效果

作者:Lipt0n

地址:http://www.jianshu.com/p/ce78da3e0ff6

声明:本文是Lipt0n原创,已获其授权发布,未经原作者允许请勿转载

RecyclerView性能和自由度相比ListView强大很多,但很恼人的是它没有像ListView一样默认提供分割线。

刚接触RecyclerView,用过才发现RecyclerView没有分割线过后,遂到网上搜解决办法才发现自定义一个ItemDecoration只要一条黑线还要写代码,好麻烦,不知道有没像我一样懒得折腾上网搜现成的,粘贴到项目直接用。

拖了很久才去解决这个问题,上网大致看了一下教程,其实不难而且自定义功能很强大。

首先新建一个类覆写ItemDecoration里面有三个方法:

 public class SimpleItemDecoration extends RecyclerView.ItemDecoration {      
     public SimpleItemDecoration(Context context) {      
     
     }           
     
     public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {         
         super.onDraw(c, parent, state);     
     }           
     
     public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {         
         super.onDrawOver(c, parent, state);      
     }       
     
     @Override     
     public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {         
         super.getItemOffsets(outRect, view, parent, state);     
     } 
 }

onDraw名字很熟悉吧,和View中的onDraw一样,是用来画东西的, 在item上画分割线就靠这个方法了.

onDrawOver 英文Over的意思在…的上面 ,可以理解成是图层关系,item的内容和分割线是第一层(要在第一层画东西要调用onDraw),而onDrawOver是第二层,位于onDraw的上面getItemOffsets看名字可以知道是设置item的偏移值,其实效果和padding一样。以上三个方法都是在RecylerView发生滑动的时候触发。

需要注意的是三个方法的都有一个RecyclerView parent,通过这个参数我们可以获取到RecyclerView的属性,例如 parent.getChildCount();获取子View的个数,但是这个并不是获取RecyclerView所有的item个数,而是当前屏幕可见的item个数。

所以画一条分割线需要的代码是这样的:

 private int wight;     
 private int height;     
 private int item_height;     
 private int item_padding;     
 private Paint paint;  
 public SimpleItemDecoration(Context context) {         
     wight=context.getResources().getDisplayMetrics().widthPixels;         
     height=context.getResources().getDisplayMetrics().heightPixels;         
     paint=new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG);         
     paint.setColor(Color.BLACK);         
     item_height=DensityUtil.dip2px(context, 1);         
     item_padding=DensityUtil.dip2px(context, 10);     
 }      
 @Override     
 public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {         
     super.onDraw(c, parent, state);         
     int count=parent.getChildCount();         
     for (int i = 0; i < count; i++) {             
         View view=parent.getChildAt(i);             
         int top=view.getTop();             
         int bottom=top+item_height;             
         c.drawRect(0,top,wight,bottom,paint);          
     }           
     .....    
 }

运行后得到如下图的效果。

接着把 item_height=DensityUtil.dip2px(context, 1);的1改成30,你会发现item的内容和黑色的分割线重合了(黑人问号脸???)

因为上面说了item和内容和onDraw中画的内容在同一图层,当然会被出现重合的情况.这个时候getItemOffsets就能派上用场了.只要在原来的item的加个偏移值(效果和在Adpater中为item设置padding的效果是一样的,只是在ItemDecoration统一处理比较合适)onDraw中画的分割线有多高,我就paddingBottom多少.

所以代码是是这样的:

再次运行代码item被挡住的问题就解决了,RecyclerView的自定义ItemDecoration就是这么简单.有点自定义View经验的人理解起来都不会难

分割线不要占满,要有和Left,Right有间距啊?

添加如下代码:

一般用到的分割线根据以上的代码再自己的按照需求稍微修改一下基本都能满足需求了.

之前在网上看到通过自定义ItemDecoration实现仿照旧版的instagram吸顶效果,感觉那种效果很好看,研究了一下发现只要理解了上面文章所说的几个方法实现起来并不难.

先来看最终效果图:

要实现吸顶的效果需要完成这些步骤:

  1. 首先需要画一条高度足够容下文字和图片的分割线.
  2. 因为是吸顶效果,所以分割线和传统的分割线一样应该是在每个item的上方而不是下方
  3. 当前屏幕可见的第一个item的Bottom<=item_height(分割线的高度) 说明可见的第一个item的底部已经超出了分割线的高度,这个时候就应该让第一条分割线随着RecyclerView向上滑动直到滑出屏幕,这个时候第二个item就取代了第一个item变成了第一个item,否则分割线一直固定不动.
  4. 判断当前屏幕的第一个可见的item是哪个
  5. 把当前屏幕可见的item进行对比,如果item的内容第一个字相同,则把它们归为一组,用一条分割线显示即可.

先来实现1和2的要求,主要代码部分如下:

注意看陈奕迅这个item的分割线是在item的上面的,并且分割线的高度已经足够容下我们稍后要绘制的内容了.

接着来实现3,怎么样才能让分割线在满足条件的时候动,不满足的时候固定?

这个时候就需要用到代码中一直没覆写的onDrawOver方法了,先来实现固定不动的分割线,代码也是非常的简单,在原来的代码上覆写onDrawOver方法(这里new了新的画笔paint2,把固定的分割线用半透明红色来作为背景,方便理解效果):

接着来实现实现: 当前屏幕可见的第一个item的Bottom<=item_height(分割线的高度)让第一条分割线随着RecyclerView向上滑动直到滑出屏幕,代码如下:

可以看到滑动时当第二item的顶部和第一个item的底部相互接触到后继续滑动的话第一个item就会慢慢向上滑动,直到第一个item完全画出屏幕,固定分割线立马回到最开始的位置和item2分割线重叠了在一起,现在可以把paint2换回paint效果会更直观,不上效果图了,可以自己去测试.

对第一次接触ItemDecoration的人来说,难点都已经讲完了,剩下的就是在分割线范围计算出合适的位置调动drawText和drawBitmap画下文字和图片,直接贴上完整的源码:(在源码注释里面已经把没有讲到的方法大致提了一下实现的原理)

自定义ItemDecoration的代码:

Activity中调用的代码

只要理解了最开始提到的ItemDecoration 的3个主要方法,再处理一下文字分组的逻辑实现起来不会太难,花点耐心还是能写出来的.

本文分享自微信公众号 - Android先生(cyg_24kshign)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-09-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小狼的世界

IE6下实现Width:auto

看了这个题目,很多人肯定觉得有点太老土了,IE6都快到末路了,不过这个方法确实非常经典,我觉得很有必要记下一笔。

9320
来自专栏互联网杂技

超全整理前端开发面试题——CSS篇(2016年)

介绍一下标准的CSS的盒子模型?低版本IE的盒子模型有什么不同的? (1)有两种,IE 盒子模型、W3C 盒子模型; (2)盒模型:内容(content)、填充...

450130
来自专栏hbbliyong

基于Three.js的360度全景--photo-sphere-viewer--简介

这个是基于three.js的全景插件  photo-sphere-viewer.js  ————————————————————————————————————...

91590
来自专栏Micro_awake web

谈谈CSS中一些比较"偏门"的小知识 前面我写了:谈谈html中一些比较"偏门"的知识,现在这篇(主要)想谈谈个人所见的CSS一些小知识点,加深印象;同时也希望有需要的人能有收获!

前面我写了:谈谈html中一些比较"偏门"的知识,现在这篇(主要)想谈谈个人所见的CSS一些小知识点,加深印象;同时也希望有需要的人能有收获! 1.常见的浏览器...

21160
来自专栏埋名

React UI 组件库【uiw】发布

高品质的UI工具包,基于React 16+的组件库。 ? 为了表示支持,点击 阅读原文 搞点Star,多多益善。

21320
来自专栏用户3030674的专栏

Android5.0新特性之——控件移动动画(初级)

最近开发,UI大牛们设计了好多很炫酷吊炸天的动画,不由得重新学习了一下5.0的ObjectAnimator动画。

15620
来自专栏web前端

Vuejs --01 起步

一、是什么      1、是一套构建用户界面的渐进式框架,Vue采用自底向上增量开发的设计           1.1     解释:框架譬如angular,是...

23750
来自专栏偏前端工程师的驿站

CSS魔法堂:Transition就这么好玩

 以前说起前端动画必须使用JS,而CSS3为我们带来transition和@keyframes,让我们可以以更简单(声明式代替命令式)和更高效的方式实现UI状态...

13230
来自专栏程序员叨叨叨

手把手教你打造RecyclerView滚动特效

最近开发中遇到这样的需求,recyclerview的item随滚动改变大小和透明度。这个效果看起来挺有动感的,似乎实现起来有点复杂,其实不然,接下来将带领大家手...

22110
来自专栏C/C++基础

CSS3制作3D水晶糖果按钮

本人仿照20个漂亮 CSS3 按钮效果及优秀的制作教程中的BonBon(Candy)Button实现了其棒棒糖果按钮,如下图所示:

13510

扫码关注云+社区

领取腾讯云代金券