作者:Jinbeen 链接:https://www.jianshu.com/p/dbb81c829e53
前言
我基本上找遍了网上所有通过ItemDecoration
设置分隔线的文章,但都不尽如意,它们大多只适用于部分情况,比如只能给线性布局设置、只能设置color
不能设置drawable
、不能去除HeaderView
部分的分割线、配置麻烦等等等。
于是我费尽周折出了两个类:SpacesItemDecoration
,GridSpaceItemDecoration
。它们基本解决了上述所有问题!
收录于开源项目:ByRecyclerView
它们有什么功能
SpacesItemDecoration
:
给LinearLayoutManager
设置
- 1、可设置
color
或drawable
- 2、可设置分割线左右或上下的间距
- 3、可设置
header
或footer
不显示分割线的个数,功能似ListView
的setHeaderDividersEnabled(ture)
- 4、支持横向或纵向
GridSpaceItemDecoration
:
给GridLayoutManager
或StaggeredGridLayoutManager
设置
- 1、可配置只在四周是否显示分割线
- 2、可设置
header
或footer
不显示分割线的个数
绘制原理
网上很多解释通过ItemDecoration
绘制分割线的原理的文章,我简单总结一下,在getItemOffsets()
方法里设置item宽度的偏移量,在onDraw()
方法里主要绘制分割线颜色。getItemOffsets
是针对每一个 ItemView
,而 onDraw
方法却是针对 RecyclerView
本身,所以在 onDraw
方法中需要遍历屏幕上可见的 ItemView
,分别获取它们的位置信息,然后分别的绘制对应的分割线。-- 参考:https://juejin.im/post/5cecef7d5188250b3a1b9173
示例图
参数配置
SpacesItemDecoration
构造方法有四个:
SpacesItemDecoration(Context context)
SpacesItemDecoration(Context context, int orientation)
SpacesItemDecoration(Context context, int orientation, int headerNoShowSize)
/**
* @param context Current context, it will be used to access resources.
* @param orientation 水平方向or垂直方向,默认SpacesItemDecoration.VERTICAL
* @param headerNoShowSize 不显示分割线的item个数 这里应该包含刷新头
* @param footerNoShowSize 尾部 不显示分割线的item个数 默认不显示最后一个item的分割线
*/
public SpacesItemDecoration(Context context, int orientation, int headerNoShowSize, int footerNoShowSize)
其他参数设置,其中setDrawable与setParam只能选择其一:
/**
* Sets the {
@link Drawable} for this divider.
*
* @param drawable Drawable that should be used as a divider.
*/
public SpacesItemDecoration setDrawable(Drawable drawable)/**
* 直接设置分割线颜色等,不设置drawable
*
* @param dividerColor 分割线颜色
* @param dividerSpacing 分割线间距
* @param leftTopPaddingDp 如果是横向 - 左边距
* 如果是纵向 - 上边距
* @param rightBottomPaddingDp 如果是横向 - 右边距
* 如果是纵向 - 下边距
*/public SpacesItemDecoration setParam(int dividerColor, int dividerSpacing, float leftTopPaddingDp, float rightBottomPaddingDp)
一个完整的设置如下:
// 设置分割线color
SpacesItemDecoration itemDecoration = new SpacesItemDecoration(recyclerView.getContext(), SpacesItemDecoration.VERTICAL, 0, 1)
.setParam(R.color.colorLine, 1, 12, 12);
recyclerView.addItemDecoration(itemDecoration);
// 设置分割线drawable
SpacesItemDecoration itemDecoration = new SpacesItemDecoration(recyclerView.getContext(), SpacesItemDecoration.VERTICAL, 0, 1)
.setDrawable(R.drawable.shape_line);
recyclerView.addItemDecoration(itemDecoration);
核心代码
这里主要解释这几个参数配置的核心代码,具体请直接见源代码:
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final int childRealPosition = parent.getChildAdapterPosition(child);
// 过滤到头部不显示的分割线
if (childRealPosition < mHeaderNoShowSize) {
continue;
}
// 过滤到尾部不显示的分割线
if (childRealPosition <= lastPosition - mFooterNoShowSize) {
// 设置drawable
if (mDivider != null) {
parent.getDecoratedBoundsWithMargins(child, mBounds);
final int bottom = mBounds.bottom + Math.round(child.getTranslationY());
final int top = bottom - mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
// 设置color
if (mPaint != null) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
// 首尾间距
int left1 = left + mLeftTopPadding;
int right1 = right - mRightBott