前言
网上设置RecycleView间隔的几种方法总结
- item布局中,设置间隔
- 自定义ItemDecoration 实现间隔,又分为两种:
2.1 使用Rect 设置left、top 、right 、bottom 设置间距,伪造间隔
2.2 使用draw 绘制间隔(onDraw、onDrawOver) - 官方默认的分割线
三种方法,无优劣之分,各有适用的场景。
方法对比
1.item布局设置分割线
1.1 顶部带分割线(LinearLayoutManager.VERTICAL)
效果

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!--分割线-->
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="#FFFFFF" />
<ImageView
android:id="@+id/img_item"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="@color/colorPrimary" />
</LinearLayout>
1.2 顶部无间距(LinearLayoutManager.VERTICAL)
效果

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/img_item"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="@color/colorPrimary" />
<!--分割线-->
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="#FFFFFF" />
</LinearLayout>
1.3分割线左右间距(LinearLayoutManager.VERTICAL)
效果

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/img_item"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="@color/colorPrimary" />
<!--分割线 设置margin-->
<View
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:background="#680707" />
</LinearLayout>
如果是LinearLayoutManager.HORIZONTAL,思路是一样。啰啰嗦嗦的。。。

2.自定义ItemDecoration设置分割线
说道ItemDecoration不得不说三个方法:
/**
* @param c 画布
* @param parent RecyleView
* @param state RecyclerView的当前状态
*/
@Override
public void onDraw(Canvas c, RecyclerView parent,RecyclerView.State state) {
/**
* @param outRect
* @param view RecycleView的itemView
* @param parent RecycleView
* @param state RecycleView 的状态
*/
@Override
public void getItemOffsets(Rect outRect,View view, RecyclerView parent, RecyclerView.State state)
/**
* @param c 画布
* @param parent RecycleView
* @param state RecycleView的状态
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state)
至于这三者的功能,您可以看下别人写的的博客(感谢,借用他的图),比较直观
onDrawOver和onDraw的区别
有个图比较的直观的
你还记的上面说的2.1、2.2 两种不同的分割线的方法吗?
就和onDraw()和getItemOffsets()方法有关。下面我们细细说来:
-
使用Rect 来设置间隔
Rect 到底是什么 ,还是上一张图(借个图,感谢作者)比较直观些。
其中绿色View 是RecycleView的item(手机上显示的item,就是绿色的部分);
外部橘色是 在Rect 设置了left 、top、righ 、bottom 后的间距,默认情况下let、top、right、bottom都是0。
Rect.left相当于 marginleft,其他类似。
View 设置了Rect 后,会有类似Margin的属性(是类似),在空间不够的情况下,可能会出现view被压缩 等情况。尤其在网格布局中。
这种设置Rect的方法,并不算是真正的设置分割线,而是利用了设置margin的间距,利用recycleView的 背景颜色作为分隔线,所有分割线的长度(高度)不可控: -
分割线长度:由recycleView得长度控制
-
分割线高度:由前一个item的rect.bottom +当前item的rect.top= 分割线的高度
效果:如下图
具体:黄色是recycleView的背景颜色;recycleView 的item 是上图中的
整个的item的背景是白色,特意设置imgView 的高度不填充item 。左右的黄色的间隔是由于设置rect.left/rect.right 。
具体的代码:
item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@android:color/white"
android:gravity="center_vertical">
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="60dp" />
</LinearLayout>
自定义LinearItemDecoration
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space ;
// Add top margin only for the first item to avoid double space between items
// if (parent.getChildPosition(view) == 0)
// outRect.top = space;
}
- 使用onDraw()来绘制间隔
分层图中,可以明显的看出来,onDraw() 绘制的面板 在itemView的下面。使用draw()即使绘制了分割线,但是由于ItemView的遮盖,还是显示不出来,所以:自定义分割线,需要使用到Rect 方法,控制item的间隔提供空间来显示绘制的分割线。我们需要获取item之间的间距,计算分割线的四个关键点坐标,绘制矩形。
效果:
具体代码
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int count = parent.getChildCount(); //recycleView中item显示在界面的个数
for (int i = 0; i < count; i++) {
View childView = parent.getChildAt(i); // 获取position的item
int index = parent.getChildAdapterPosition(childView); // 获取itemView所在的位置
if (index != 0) {
ViewGroup.MarginLayoutParams childLp = (ViewGroup.MarginLayoutParams) ((ViewGroup) childView)
.getChildAt(0).getLayoutParams(); //获取itemView中ImageView的margin值
int devideLeft = childLp.leftMargin; // 设置矩形left
int rectMiddleLine = 30 / 2; // 分割线一半的高度
int topLine = childView.getTop() - rectMiddleLine - devideHeight / 2;
int devideTop = topLine; // 设置分割线的top
int devideRight = parent.getWidth() - childLp.rightMargin; // 设置矩形right
int devideBottom = childView.getTop() - rectMiddleLine + devideHeight / 2; // 设置分割线的bottom
c.drawRect(devideLeft, devideTop, devideRight, devideBottom, paint); // 绘制分割线矩形
}
}
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (parent.getChildAdapterPosition(view) != 0) {
outRect.top = 30; // item之间的距离
devideHeight = 10; // 自绘制的间距的矩形的高度
}
}
其中红色的是我们自己绘制的分割线,黄色的还是recycleView的背景颜色,白色是itemView的背景颜色。
- 使用onDrawOver绘制
方法和onDrawOver类似,只不过是绘制在itemView上层。