前言

RecyclerView,在开发当中使用非常频繁的一个控件,今天,主要讲解以下两个问题

  • 添加分割线
  • item 间距的平均分布

文章目录如下

addItemDecoration 方法简介
如何添加分割线
addItemDecoration 如何实现间隔平均分布
如何找到我

程序员徐公,五年中大厂开发经验,助你升职加薪,带你走进大厂

  1. 公众号程序员徐公回复黑马,获取 Android 学习视频
  2. 公众号程序员徐公回复徐公666,获取简历模板,教你如何优化简历,走进大厂
  3. 公众号程序员徐公回复面试,可以获得面试常见算法,剑指 offer 题解
  4. 公众号程序员徐公回复马士兵,可以获得马士兵学习视频一份


addItemDecoration 方法简介

我们先来看一下 addItemDecoration 方法

官网链接

Add an RecyclerView.ItemDecoration to this RecyclerView. Item decorations can affect both measurement and drawing of individual item views.

Item decorations are ordered. Decorations placed earlier in the list will be run/queried/drawn first for their effects on item views. Padding added to views will be nested; a padding added by an earlier decoration will mean further item decorations in the list will be asked to draw/pad within the previous decoration’s given area.

简单来来说,ItemDecoration 是 itemView 的装饰,可以影响 itemView 的 measurement 和 draw

ItemDecoration 主要有几个方法

getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)

Retrieve any offsets for the given item. Each field of outRect 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.

简单点说:可以影响 item 的大小,类似于在 item 中设置 padding 和 margin

void onDraw (Canvas c, RecyclerView parent, RecyclerView.State state)

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.

在提供给RecyclerView的画布上绘制任何适当的装饰。通过此方法绘制的任何内容都将在绘制项目视图之前绘制,因此将显示在 item 视图下面

void onDrawOver (Canvas c, RecyclerView parent, RecyclerView.State state)

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.

在提供给RecyclerView的画布上绘制任何适当的装饰。通过此方法绘制的任何内容都将在绘制项目视图之后绘制,因此将出现在 item 视图上面。


如何添加分割线

RecyclerViewDivider,已支持以下功能

  1. 自定义分割线,设置 drawable
  2. 设置分割线高度,颜色
  3. 设置分割线距离屏幕左边,右边的距离
  4. 设置是否显示最后一条分割线

详情代码见 RecyclerViewSample

实现思路

我们知道 RecyclerView 没有像之前 ListView 提供 divider 属性,设置分割线的话有挺多人在 itemView 的布局里面加个 1dp 左右的 view,根据业务场景设置是否可见。这是其中的一种方法。

但其实,我们也可以使用 recyclerView.addItemDecoration() 来实现,主要需要重写 getItemOffsets 和 onDraw 方法

思路很简单

  1. 重写 getItemOffsets 方法,加上 divider 的高度,影响 itemView 的最终 size
  2. 在 onDraw 方法,根据 LinearLayoutManager 的方向分别绘制分割线
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {super.getItemOffsets(outRect, view, parent, state);outRect.set(0, 0, 0, mDividerHeight);
}@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {super.onDraw(c, parent, state);if (mOrientation == LinearLayoutManager.VERTICAL) {drawVerticalDivider(c, parent);} else {drawHorizontalDivider(c, parent);}
}
//Draw item dividing line
private void drawVerticalDivider(Canvas canvas, RecyclerView parent) {// mLeftOffset 为自己设置的左边偏移量final int left = parent.getPaddingLeft() + mLeftOffset;// mRightOffset 为设置的右边偏移量final int right = parent.getMeasuredWidth() - parent.getPaddingRight() + mRightOffset;final int childSize = parent.getChildCount();if (childSize <= 0) {return;}// 从第一个 item 开始绘制int first = mStart;// 到第几个 item 绘制结束int last = childSize - mEnd - (mIsShowLastDivider ? 0 : 1);Log.d(TAG, " last = " + last + " childSize =" + childSize + "left = " + left);if (last <= 0) {return;}for (int i = first; i < last; i++) {drawableVerticalDivider(canvas, parent, left, right, i, mDividerHeight);}}private void drawableVerticalDivider(Canvas canvas, RecyclerView parent, int left, int right, int i, int dividerHeight) {final View child = parent.getChildAt(i);if (child == null) {return;}RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();final int top = child.getBottom() + layoutParams.bottomMargin;final int bottom = top + dividerHeight;// 适配 drawableif (mDivider != null) {mDivider.setBounds(left, top, right, bottom);mDivider.draw(canvas);}// 适配分割线if (mPaint != null) {canvas.drawRect(left, top, right, bottom, mPaint);}
}

Item 间距平均分布

针对 GridLayoutManager 的

在 Android 开发当中,我们经常会看到这样的界面,

一般来说,可能有以下几种需求:

  1. 要求第一列和最后一列距离屏幕的距离 A 是固定的,其余每个 item 之间的距离 B 也是固定的(但 A 不等于 B)
  2. 要求第一列和最后一列距离屏幕的距离 A 是固定的,item 的大小是固定的,其余每个 item 之间的距离跟随分辨率的大小变化
  3. 第一行距离顶部的距离可以设置,最后一行距离底部的距离可以设置

思路分析

首先,我们知道,对于 GridLayoutmanager ,当我们设置的 spancount 为 3 的时候,那么每个 item
的最大宽度为 itemMaxW = recycylerW / spancount = recycylerW / 3.

假设我们 spancount 为 3,那么在不设置 itemDercation 的情况下它的分布是这样的,可以看到第一列与最后一行的距离是不一样的

而加上 itemDercation 之后,我们所看到的 item 是这样的,因此,我们可以分别对每个 item 的 ouctRect 进行处理

核心代码如下:

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {super.getItemOffsets(outRect, view, parent, state);int top = 0;int left;int right;int bottom;int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();mSpanCount = getSpanCount(parent);int childCount = parent.getAdapter().getItemCount();// 屏幕宽度-View的宽度*spanCount 得到屏幕剩余空间int maxDividerWidth = getMaxDividerWidth(view);int spaceWidth = mFirstAndLastColumnW;//首尾两列与父布局之间的间隔// 除去首尾两列,item与item之间的距离int eachItemWidth = maxDividerWidth / mSpanCount;int dividerItemWidth = (maxDividerWidth - 2 * spaceWidth) / (mSpanCount - 1);//item与item之间的距离left = itemPosition % mSpanCount * (dividerItemWidth - eachItemWidth) + spaceWidth;right = eachItemWidth - left;bottom = dividerItemWidth;// 首行if (mFirstRowTopMargin > 0 && isFirstRow(parent, itemPosition, mSpanCount, childCount)) {top = mFirstRowTopMargin;}//最后一行if (isLastRow(parent, itemPosition, mSpanCount, childCount)) {if (mLastRowBottomMargin < 0) {bottom = 0;} else {bottom = mLastRowBottomMargin;}}Log.i(TAG, "getItemOffsets: dividerItemWidth =" + dividerItemWidth + "eachItemWidth = " + eachItemWidth);Log.i(TAG, "getItemOffsets: itemPosition =" + itemPosition + " left = " + left + " top = " + top+ " right = " + right + " bottom = " + bottom);outRect.set(left, top, right, bottom);
}

在代码中使用

mRecyclerView.setLayoutManager(layoutManager);
int firstAndLastColumnW = DisplayUtils.dp2px(this, 15);
int firstRowTopMargin = DisplayUtils.dp2px(this, 15);
GridDividerItemDecoration gridDividerItemDecoration =new GridDividerItemDecoration(this, firstAndLastColumnW, firstRowTopMargin, firstRowTopMargin);
gridDividerItemDecoration.setFirstRowTopMargin(firstRowTopMargin);
gridDividerItemDecoration.setLastRowBottomMargin(firstRowTopMargin);
mRecyclerView.addItemDecoration(gridDividerItemDecoration);
List<Integer> imageList = DataUtils.produceImageList(30);
ImageAdapter imageAdapter = new ImageAdapter(this, imageList);mRecyclerView.setAdapter(imageAdapter);

针对横向的 LinearlayoutManager

@Override
public void getItemOffsets(Rect outRect, View view,RecyclerView parent, RecyclerView.State state) {int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();int childCount = parent.getAdapter().getItemCount();if (itemPosition == 0) {outRect.left = firstAndlastRect.left;outRect.right = firstAndlastRect.right;outRect.bottom = firstAndlastRect.bottom;outRect.top = firstAndlastRect.top;return;}if (itemPosition == childCount - 1) {outRect.left = 0;outRect.right = firstAndlastRect.left;outRect.bottom = firstAndlastRect.bottom;outRect.top = firstAndlastRect.top;return;}setOutRect(outRect, space);
}
int j = DisplayUtils.dp2px(this, 15);
Rect firstAndLastRect = new Rect(j, i, i, 0);
HorizontalSpacesDecoration spacesDecoration = new HorizontalSpacesDecoration(rect, firstAndLastRect);
mRecyclerView.addItemDecoration(spacesDecoration);
List<Integer> integers = DataUtils.produceImageList(R.mipmap.ty1, 30);
ImageAdapter imageAdapter = new ImageAdapter(this, integers);
mRecyclerView.setAdapter(imageAdapter);

RecyclerViewSample:https://github.com/gdutxiaoxu/RecyclerViewSample

找到我

这篇文章,加上一些 Demo,足足花了我几个晚上的时间,我是站在巨人的肩膀上成长起来的,同样,我也希望成为你们的巨人。觉得不错的话可以关注一下我的微信公众号程序员徐公,在此感谢各位大佬们。主要分享

  1. Android 开发相关知识:包括 java,kotlin, Android 技术。
  2. 面试相关分享:包括常见的面试题目,大厂面试真题、面试经验套路分享。
  3. 算法相关学习笔记:比如怎么学习算法,leetcode 常见算法总结,跟大家一起学习算法。
  4. 时事点评:主要是关于互联网的,比如小米高管屌丝事件,拼多多女员工猝死事件等

希望我们可以成为朋友,成长路上的忠实伙伴!

RecyclerView addItemDecoration 的妙用 - item 间距平均分布和添加分割线相关推荐

  1. android item间距,RecyclerView 设置item之间的间距

    RecyclerView没有可以直接设置间距的属性,但看了源码之后可以发现RecyclerView有个内部类ItemDecoration,可以用ItemDecoration来装饰一个item,所以继承 ...

  2. Android 解决RecyclerView瀑布流刷新之后Item位置改变

    解决RecyclerView瀑布流刷新之后Item位置改变 为了测试RecyclerView瀑布流效果,每个Item的高度采取了随机高度,导致每次刷新的时候,重新随机出来的高度和原来的不一致,会导致I ...

  3. Recyclerview中最后一个可见Item的位置以及是否滑动到底部

    目前很多项目里都使用Recyclerview来做开发了,但是对于Recyclerview不是很了解可能会遇到各种问题,下面就对怎样判断Recyclerview中的最后一个item做判断! mRecyc ...

  4. html怎么让导航栏平均分布,CSS 怎么让按钮平均分布

    CSS 怎么让按钮平均分布 等分布局是指子元素平均分配父元素宽度的布局方式, 本文将介绍实现等分布局的 4 种方式 一, float 缺点: 结构和样式存在耦合性, IE7 - 浏览器下对宽度百分比取 ...

  5. Android开发之约束布局平均分布|ConstraintLayout平均分布|约束布局均匀分布|ConstraintLayout均匀分布

    老路子先看效果图 1.先画7个小球会全部重叠在一起 <?xml version="1.0" encoding="utf-8"?> <andro ...

  6. 自动布局按钮排列平均分布

    需要实现如下图所示的主页面布局,需要两排按钮,每一排都自动平均分布,Android的话直接用LinearLayout水平布局,并设置layout_weight即可,对于iOS,网上有使用代码实现,感觉 ...

  7. Grid平均分布自动换行

    前言:当我们在布局商品列表的时候,需要平均分布和自动换行功能,在此使用grid简单快捷布局实现该功能,这里以微信小程序为例. wxml部分 <view class="container ...

  8. flex平均分布换行后自动对齐

    目的效果: 如何可以使用flex布局 进行平均分布,又可以换行呢? 我最开始是这样做的: display: flex;display: -webkit-flex;justify-content: sp ...

  9. TD数量不确定时如何让其宽度平均分布

    D数量不确定时如何让其宽度平均分布? 答案很简单,我们只要在table里面加上一下代码就可以实现. table { width: 100%; table-layout: fixed; } 转载于:ht ...

最新文章

  1. 杂谈---改变个人习惯
  2. pandas批量为列名添加字符并重命名实战
  3. 深入Atlas系列:客户端网络访问基础结构示例(1) - 编写并使用自定义的WebRequestExecutor...
  4. 欧文分校计算机新sat多少分录取,加州大学欧文分校SAT成绩要求
  5. 树莓派安装python3.5_梦见树_周公解梦梦到树是什么意思_做梦梦见树好不好_周公解梦官网...
  6. Mongodb 安装和启动
  7. 实际工程中加快 Java 代码编写的小提示
  8. solidity 合约权限授权_智能合约的调配模式:如何让你的智能合约安全协作?
  9. sql 时态表的意义_SQL Server 2016中的时态表的概念和基础
  10. Linux 命令(27)—— echo 命令
  11. Murano Weekly Meeting 2016.07.05
  12. [病毒]exp1orer.exe
  13. html手机验证码登录页面代码,htmlunit 模拟登录 数字验证码(示例代码)
  14. 相同名字比对公式,相似度对比算法
  15. ubuntu安装搜狗输入法,并解决输入框一直显示在左下角的问题
  16. 服务器管理口IP及账号密码(知识汇总)
  17. python代码设计测试用例_《带你装B,带你飞》pytest成神之路2- 执行用例规则和pycharm运行的三种姿态...
  18. android studio打包apk,jnilibs中的so库未被加载到apk内
  19. getopt()函数简介
  20. 计算机传奇人物之詹姆斯.高斯林

热门文章

  1. html 超链接 ppt,《用HTML建立超链接》PPT课件.ppt
  2. 常见的User-Agent及免费代理IP网站
  3. 【反思】吉首大学第九届“新星杯”大学生程序设计大赛(暨新生网络同步赛)
  4. 【什么是服务器托管?为什么要托管呢?】
  5. 2016年3月15日Android实习日记
  6. 小微企业调查数据库(2015)
  7. jQuery基础二DOM操作
  8. OSI七层模型、TCP/IP四层模型
  9. linux学习34-运维自动化之ANSIBLE
  10. python 长字符串 ,每行指定长度输出