1、ItemDecoration简介

Recyclerview是我们日常开发中使用频率比较高的的控件,而其中的ItemDecoration作为布局装饰又能很方便的帮助我们定义分割线,列表排行效果以及设置布局悬浮置顶效果等,所以有必要去了解ItemDecoration的诸多细节。

2、基本原理

我们先关注下实现RecyclerView.ItemDecoration必须要实现的三个方法,#getItemOffsets()用于在Item周围设置上下左右的间隙,然后我们可以使用#onDraw()在间隙绘制分割线以及其他图案等;而#onDrawOver()则是在RecyclerView布局上面绘制图案

public class MyDecoration extends RecyclerView.ItemDecoration{/*** step1 相当于itemView外还有一个矩形,我们可以自由在itemview上下左右设置空余部分,
通过outRect 的left,top,right,bottom 来进行设置,我们可在这块控件进行绘制* 目标针对每一个item个体*/@Overridepublic void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {super.getItemOffsets(outRect, view, parent, state);}/*** step2 在item间绘制  常用于绘制分割线* 针对整个Recyclerview 绘制需要循环遍历item子布局 然后方能针对具体的item进行增加绘制*/@Overridepublic void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {super.onDraw(c, parent, state);}/*** 在item上绘制*/@Overridepublic void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {super.onDrawOver(c, parent, state);}
}

2.1 getItemoffsets在RecyclerView源码中作用时机

manager#getItemDecorInsetsForChild

为指定view计算分割线矩形

    Rect getItemDecorInsetsForChild(View child) {RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)child.getLayoutParams();if (!lp.mInsetsDirty) {return lp.mDecorInsets;} else if (this.mState.isPreLayout() && (lp.isItemChanged() || lp.isViewInvalid())) {return lp.mDecorInsets;} else {Rect insets = lp.mDecorInsets;insets.set(0, 0, 0, 0);int decorCount = this.mItemDecorations.size();for(int i = 0; i < decorCount; ++i) {this.mTempRect.set(0, 0, 0, 0);((RecyclerView.ItemDecoration)this.mItemDecorations.get(i)).getItemOffsets(this.mTempRect, child, this, this.mState);insets.left += this.mTempRect.left;insets.top += this.mTempRect.top;insets.right += this.mTempRect.right;insets.bottom += this.mTempRect.bottom;}lp.mInsetsDirty = false;return insets;}}// 测量的时候 当作padding值放入其中public void measureChild(@NonNull View child, int widthUsed, int heightUsed) {RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)child.getLayoutParams();Rect insets = this.mRecyclerView.getItemDecorInsetsForChild(child);widthUsed += insets.left + insets.right;heightUsed += insets.top + insets.bottom;int widthSpec = getChildMeasureSpec(this.getWidth(), this.getWidthMode(), this.getPaddingLeft() + this.getPaddingRight() + widthUsed, lp.width, this.canScrollHorizontally());int heightSpec = getChildMeasureSpec(this.getHeight(), this.getHeightMode(), this.getPaddingTop() + this.getPaddingBottom() + heightUsed, lp.height, this.canScrollVertically());if (this.shouldMeasureChild(child, widthSpec, heightSpec, lp)) {child.measure(widthSpec, heightSpec);}}

manager#calculateItemDecorationsForChild

manager向外部提供的获取分割线矩形数据的api

        public void calculateItemDecorationsForChild(@NonNull View child, @NonNull Rect outRect) {if (this.mRecyclerView == null) {outRect.set(0, 0, 0, 0);} else {Rect insets = this.mRecyclerView.getItemDecorInsetsForChild(child);outRect.set(insets);}}

可解决问题:如何获取指定itemView的分割线的高度

Rect rect = new Rect();
View view =  mRvConflict.getLayoutManager().findViewByPosition(1);if (view != null){mRvConflict.getLayoutManager().calculateItemDecorationsForChild(view,rect);Log.e("decoration", "高度 = "+rect.height() );}

3. 分割线使用

3.1无任何分割线的RecyclerView

 private void initAdapter() {mMyRecvAdapter = new MyRecvAdapter(mContext,mList);LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);mRecyclerView.setLayoutManager(linearLayoutManager);mRecyclerView.setAdapter(mMyRecvAdapter);}

相信大家对如何说些一个RecyclerView列表再熟悉不过了吧,不过推荐大家可以使用BRVAH点击打开链接出来蛮久的了,可以大大提升开发效率。

3.2 一行代码添加系统分割线

mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));

运行效果:

                         

分析一下:  RecyclerView 为我们提供的DividerItemDecoration的用于添加分割线的类中 代码其实不多,主要是继承了ItemDecoration并实现了 getItemOffsets()和onDra()方法,这里的getItemOffsets( )实际上是在条目之间分配一块矩形区域用来放置我们的分割线,注意一下方法参数Rect outRect,而通过onDraw( )方法把条目画在刚刚申请的间隔矩形中。没错就是这么简单,有兴趣的可以对照着源码细看一下。

public class DividerItemDecoration extends RecyclerView.ItemDecoration {......@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent,RecyclerView.State state) {if (mOrientation == VERTICAL) {outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());} else {outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);}// 设置矩形区域 // set(left,top,right,bottom) = outRect.left = left ...}@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {if (parent.getLayoutManager() == null) {return;}if (mOrientation == VERTICAL) {drawVertical(c, parent);} else {drawHorizontal(c, parent);}}.......
}

getitemOffset可依据混排的条目数 设置间距效果

        View view = null;GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams();int spanSize = layoutParams.getSpanSize();// 获得每行的下标 0,1int spanIndex = layoutParams.getSpanIndex();

3.3 不用系统的分割线,自己设定分割线的宽度和颜色

看下面只需要知己设置drawable就可以了,你想要什么形状就可以添加什么样的形状。

 DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);dividerItemDecoration.setDrawable(ContextCompat.getDrawable(this,R.drawable.shape_devider_line_red));mRecyclerView.addItemDecoration(dividerItemDecoration);

如上右图所示

3. 4 扩展

前面已经分析了DeivderItemDecoration的实现了,我们也可以自己手动撸一个来实现不是嘛,我们可以发现前面虽然是可以设置drawable进去,那么每次还需要写一个drawable文件或者弄张.9图进去,但通常的业务环境是只需要带颜色的线条就可以了吧,所以基于此我们可以自己手写一个。

直接上代码了额:

/*** @author zxl on 2018/7/14.*         discription: 自定义分割线支持水平和垂直布局 设置默认,图片和颜色为分割线*/public class MyRecyclerViewDivider extends RecyclerView.ItemDecoration {private Paint mPaint;private Drawable mDivider;private int mDividerHeight;private int mOrientation;/***  系统默认的分割线* */private static final int[] ATTRS = new int[]{android.R.attr.listDivider};/***  设置默认的分割线*  @param orientation 指代分割线的方向* */public MyRecyclerViewDivider(Context context, int orientation) {this.mDividerHeight = 2;if(orientation != 1 && orientation != 0) {throw new IllegalArgumentException("请输入正确的参数!");} else {this.mOrientation = orientation;TypedArray a = context.obtainStyledAttributes(ATTRS);this.mDivider = a.getDrawable(0);a.recycle();}}/***  设置图片资源为分割线* */public MyRecyclerViewDivider(Context context, int orientation, int drawableId) {this(context, orientation);this.mDivider = ContextCompat.getDrawable(context, drawableId);this.mDividerHeight = this.mDivider.getIntrinsicHeight();}/***  设置线条颜色和高度给分割线* */public MyRecyclerViewDivider(Context context, int orientation, int dividerHeight, int dividerColor) {this(context, orientation);this.mDividerHeight = dividerHeight;this.mPaint = new Paint(1);this.mPaint.setColor(dividerColor);this.mPaint.setStyle(Paint.Style.FILL);}@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {super.getItemOffsets(outRect, view, parent, state);outRect.set(0, 0, 0, this.mDividerHeight);}@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {super.onDraw(c, parent, state);if(this.mOrientation == 1) {this.drawVertical(c, parent);} else {this.drawHorizontal(c, parent);}}private void drawHorizontal(Canvas canvas, RecyclerView parent) {canvas.save();final  int left;final int right;// 判断RecyclerView是否要裁剪padding值if (parent.getClipToPadding()){// 需要裁剪那么就进行裁剪left = parent.getPaddingLeft();right = parent.getWidth()-parent.getPaddingRight();// 裁剪rv可视区域,  限制视图在该区域内是可见的,很重要的,这里canvas.clipRect(left,parent.getPaddingTop(),right,parent.getHeight()-parent.getPaddingBottom());}else {//  不裁剪则宽贼为rv的宽left = 0;right = parent.getWidth();}int childSize = parent.getChildCount();for(int i = 0; i < childSize; ++i) {View child = parent.getChildAt(i);// 获得item的信息包RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams)child.getLayoutParams();// 分割线顶部 = item的底部 + item到底部的距离 + 动画偏移int top = child.getBottom() + layoutParams.bottomMargin + Math.round(ViewCompat.getTranslationY(child));// 分割线底部 =  分割线底部 + 高度int bottom = top + this.mDividerHeight;if(this.mDivider != null) {this.mDivider.setBounds(left, top, right, bottom);this.mDivider.draw(canvas);}if(this.mPaint != null) {canvas.drawRect((float)left, (float)top, (float)right, (float)bottom, this.mPaint);}}canvas.restore();}private void drawVertical(Canvas canvas, RecyclerView parent) {canvas.save();final int top;final int bottom;if (parent.getClipToPadding()){top = parent.getPaddingTop();bottom = parent.getHeight() - parent.getPaddingBottom();canvas.clipRect(parent.getPaddingLeft(),top,parent.getWidth()-parent.getPaddingRight(),bottom);}else {top  = 0;bottom = parent.getHeight();}int childSize = parent.getChildCount();for(int i = 0; i < childSize; ++i) {View child = parent.getChildAt(i);RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams)child.getLayoutParams();int left = child.getRight() + layoutParams.rightMargin + Math.round(ViewCompat.getTranslationX(child));int right = left + this.mDividerHeight;if(this.mDivider != null) {this.mDivider.setBounds(left, top, right, bottom);this.mDivider.draw(canvas);}if(this.mPaint != null) {canvas.drawRect((float)left, (float)top, (float)right, (float)bottom, this.mPaint);}}canvas.restore();}
}

用法如下也是很简单,优点不用多说既囊括了系统提供的也支持drawable设置而且支持简易的线条颜色等,用途很大对的吧。

mRecyclerView.addItemDecoration(new MyRecyclerViewDivider(this, LinearLayoutManager.HORIZONTAL,2,ContextCompat.getColor(this,R.color.colorAccent)));

效果我下方左图所示

        

弄个表格出来

以下为 addItemDecoration的源码,可以发现的是可以设置多条分割线,哈哈,那么我们不就能画表格了嘛,6666

    public void addItemDecoration(ItemDecoration decor, int index) {if (mLayout != null) {mLayout.assertNotInLayoutOrScroll("Cannot add item decoration during a scroll  or"+ " layout");}if (mItemDecorations.isEmpty()) {setWillNotDraw(false);}if (index < 0) {mItemDecorations.add(decor);} else {mItemDecorations.add(index, decor);}markItemDecorInsetsDirty();requestLayout();}

activity中的代码如下:

        mMyRecvAdapter = new MyRecvAdapter(mContext,mList);mRecyclerView.addItemDecoration(new MyRecyclerViewDivider(this, LinearLayoutManager.HORIZONTAL,2,ContextCompat.getColor(this,R.color.colorAccent)));mRecyclerView.addItemDecoration(new MyRecyclerViewDivider(this,LinearLayoutManager.VERTICAL,2,ContextCompat.getColor(this,R.color.colorAccent)));mRecyclerView.setLayoutManager(new GridLayoutManager(this,3));mRecyclerView.setAdapter(mMyRecvAdapter);

运行效果如上图所示。

Android 活用RecyclerView分割线相关推荐

  1. RecyclerView分割线的技巧

    RecyclerView分割线的技巧 真的很简单,因为方法别人都已经写好了,不多说了还是看源码: package com.xiayiye.yhsh.recyclerviewdemo;import an ...

  2. 万能RecyclerView分割线扩展

    该万能分割线参考自博客:RecyclerView的万能分割线_pengkv的博客-CSDN博客_android recyclerview 分割线 在他的基础上添加了距离左右边距的属性. recycle ...

  3. Android 控件 RecyclerView 看这篇就够了

    [Android 控件 RecyclerView] 概述 RecyclerView是什么 从Android 5.0开始,谷歌公司推出了一个用于大量数据展示的新控件RecylerView,可以用来代替传 ...

  4. Android 控件 RecyclerView

    [Android 控件 RecyclerView] 概述 RecyclerView是什么 从Android 5.0开始,谷歌公司推出了一个用于大量数据展示的新控件RecylerView,可以用来代替传 ...

  5. android学习日记 RecyclerView的简单使用

    android学习日记 RecyclerView的简单使用 文章目录 android学习日记 RecyclerView的简单使用 一.如何使用RecyclerView? 二.使用步骤 1.首先在bui ...

  6. Android Studio开发RecyclerView遇到的各种问题以及解决(一)

    Android Studio开发RecyclerView遇到的各种问题以及解决(一) 参考文章: (1)Android Studio开发RecyclerView遇到的各种问题以及解决(一) (2)ht ...

  7. Android SrcollView嵌套recyclerView的使用

    今天,简单讲讲Android里使用SrcollView嵌套recyclerView需要注意的地方. 不废话了直接上代码,在使用时加上下面的代码就可以 recyclerView.setLayoutMan ...

  8. Android 高级编程 RecyclerView 控件的使用

    RecyclerView 是Android 新添加的一个用来取代ListView的控件,它的灵活性与可替代性比listview更好. 看一下继承关系: ava.lang.Object    ↳ and ...

  9. Android侧滑删除-RecyclerView轻松实现高效的侧滑菜单

    1 删除整个RecyclerView hisList.clear();   hisAdapter.notifyDataSetChanged(); mScanListAdapter.setNewData ...

最新文章

  1. pymysql报错:pymysql.err.InterfaceError: (0, '')
  2. phpStudy项目目录无法访问(报错500、400)
  3. SVN centos6.3
  4. for in 和 for of 的区别
  5. python判断能否形成等差数列
  6. python源码精要(5)-C代码规范
  7. generator 和 yield的使用
  8. FCKeditor + smarty
  9. Linux并发与竞争
  10. java定时运行一个url_Swift 4:如何异步使用URLSessionDataTask但请求是否在一个定时队列中?...
  11. Java抽象类、接口和内部类
  12. ue4渲染速度太慢_技术汇丨如何在UE4中实现最佳性能和高质量视觉效果
  13. Active Directory Get User's groups using LDAP
  14. Windows Embedded CE 中断结构分析
  15. Hadoop运行环境搭建
  16. B2C商城系统源码 单商户B2C商城系统源码
  17. 计算机原理与接口技术论文,微机原理与接口技术综述论文
  18. M5000 全谱直读光谱仪
  19. 游戏项目导出AAB包上传谷歌提示超过150M的解决方案
  20. IT行业岗位薪资大调查:收入最高的职位是什么?

热门文章

  1. 关于计算机英语手抄报全国一等奖,【英语手抄报内容资料】_”我的学校“英语手抄报内容...
  2. 使用telnet连接qq pop服务器拉取邮件
  3. 洛谷P3899 [湖南集训]谈笑风生
  4. 阅读笔记--神经网络与深度学习(邱锡鹏)
  5. Java1.8接口方法都是抽象,判断(1分) Java接口中所有的方法都是抽象的。
  6. 张远龙高性能服务器,荆楚匠人:张远龙巧手妙思 葫芦上绘出精彩人生
  7. C# 微信企业号--发送消息
  8. 实验4-1-12 黑洞数
  9. SpringCloud(2)--服务调用
  10. 算法面试用c还是python_排序算法(C语言+Python版)宝宝再也不怕面试官写排序算法了...