RecyclerView无法像ListView直接设置分割线,但是提供了ItemDecoration类来设置,有一个实现类DividerItemDecoration提供了一个简单的分隔线,如果想自定义可以继承ItemDecoration,参考DividerItemDecoration来写。
1.主要实现方法
public class MyLinearDecoration extends RecyclerView.ItemDecoration {
//绘制自定义的分隔线,这个绘制和item的View属于同一位面,分隔线太大会阻挡视图
//这个绘制大小要配合getItemOffsets中设置的分隔线空间
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c,parent,state);
}
//设置分隔线的大小,留出画分隔线的空间
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
}
//Over是 在...之上的意思,所以他是在onDraw绘制位面的上一层进行绘制,他和onDraw相当于2层画布
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
}
}
2.具体的实现
public class MyLinearDecoration extends RecyclerView.ItemDecoration {
Paint paint;
Drawable drawable;
Rect mBounds = new Rect();
public MyLinearDecoration(Drawable drawable) {
super();
paint = new Paint();
paint.setColor(Color.RED);
this.drawable = drawable;
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c,parent,state);
int right = 0;
int left = 0;
c.save();
//这个if else是参照DividerItemDecoration,可以提高点性能,减少画布大小,
//如果recyclerView设置了Padding,我们没必要获取整个画布,获取减去padding的
//才是我们真正能够操作的画布
if (parent.getClipToPadding()) {
int top = parent.getPaddingTop();
int bottom = parent.getPaddingBottom();
left = parent.getPaddingLeft();
right = parent.getWidth()-parent.getPaddingRight();
c.clipRect(left,top,right,parent.getHeight() - bottom);
}else{
left = 0;
right = parent.getWidth();
}
//下面的操作,遍历Item,为Item绘制想要的分隔线
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View view = parent.getChildAt(i);
//获取这个Item的包含了Decoration和Margin的范围,相当于加上getItemOffsets设置的大小和Margin大小后,
//这个Item的左,上,右,下的坐标
parent.getDecoratedBoundsWithMargins(view, mBounds);
//这个注释掉的是按照我自己的想法设置的绘制边界,测试也没问题,我从示例中得出结论是
//mBounds得到的就是每个RecyclerView的Item加上间隔和margin后的最终所处的四个方位的坐标,
//那么我们绘制Decoration的底部
//就应该是mBounds.bottom,高度就应该是底部坐标减去分隔线的高度
//final int bottom = mBounds.bottom;
//final int top = mBounds.bottom - drawable.getIntrinsicHeight();
//DividerItemDecoration中的示例是加了一个Math.round(view.getTranslationY()),这个获取的是这个View相对于他个
//getTop的距离,我Debug查看了获取的值,一直为0,暂时没太明白这样写的意思。
final int bottom = mBounds.bottom + Math.round(view.getTranslationY());
final int top = bottom - drawable.getIntrinsicHeight();
//这是我在构造器中传入的Drawable要绘制到的画布的范围
drawable.setBounds(left, top, right, bottom);
drawable.draw(c);
}
c.restore();
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
//这个设置的意思是,在Item的底部加上一段距离,让分隔线画在这个范围
//不设置的话,分隔线会画到Item的视图上,造成重合
//如果你的onDraw没有给出自己的实现,只是通过这个方法设置一块区域,那么也会
//出现一段距离,背景色是这个界面的背景色
outRect.bottom = drawable.getIntrinsicHeight();
}
}
底部空出了这个Drawable高度的距离,也就是红色的部分
这个是垂直方向的LinearLayoutManager的绘制方式,如果是水平或者GridLayoutManager要注意考虑设置
间隔线范围的位置是底部还是右边
GridLayoutManager要注意边界的Item可能有的不需要加分隔,要注意。
有什么意见和错误欢迎提出。