文章目录
一 前言
效果:
目标就是:在聊天界面和个人信息这样的界面中,基本上就是一个RecyclerView了。如果不会自定义分割线,就只能很丑陋了w
本次的参考资料:
RecyclerView之ItemDecoration
(译文)RecyclerView之ItemDecoration由浅入深
深入理解 RecyclerView 系列之一:ItemDecoration
二 自定义ItemDecoration分割线上手
2.1 什么是ItemDecoration
我们之前写的RecyclerView设置分割线的方法如下:
recyclerView.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL));
然后粗略一查就知道,想要完成自定义分割线,需要的是自定义ItemDecoration。然后在MD官网里,我们看到标星号,写日期等也都是靠继承ItemDecoration之后完成。ItemDecoration到底是什么?
直译:条目装饰,顾名思义,ItemDecoration是对Item起到了装饰作用,更准确的说是对item的周边起到了装饰的作用,通过下面的图应该能帮助你理解这话的含义。
上图中已经说到了,
getItemOffsets()就是设置item周边的偏移量(也就是装饰区域的“宽度”)。
而onDraw()才是真正实现装饰的回调方法,通过该方法可以在装饰区域任意画画,
onDrawOver(),可以绘制在内容的上面,覆盖内容
2.2 getItemOffsets()方法
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
@NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
}
参数解释:
outRect:
深入理解 RecyclerView 系列之一:ItemDecoration
getItemOffsets 中为 outRect 设置的4个方向的值,将被计算进所有 decoration 的尺寸中,而这个尺寸,被用来计算 RecyclerView 每个 item view 的大小(包括 item view 的宽高,padding,以及这个 insets)。
所以在2.1中说的,getItemOffsets()就是设置item周边的偏移量其实就是通过这个outRect来设置。它额外给每个item配置一个空间。
源码中是这样设置的:所以4个参数顺序也如下。左顶右底。但是却不是画矩形,不是画矩形。所以并非两对坐标。
for (int i = 0; i < decorCount; i++) {
mTempRect.set(0, 0, 0, 0);
mItemDecorations.get(i).getItemOffsets(mTempRect, child, this, mState);
insets.left += mTempRect.left;
insets.top += mTempRect.top;
insets.right += mTempRect.right;
insets.bottom += mTempRect.bottom;
}
关于insets:它是 LayoutManager 排列 child 时用的一个空间大小,说它是 child 的padding,确实不妥,child 所占用的空间大小,应该是宽高 + padding + insets。
尝试:
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
@NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.bottom = 30;
//或者
//outRect.set(0, 0, 0, 30);
}
效果
2.3 onDraw()方法
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
}
这个方法参数有画布canvas和RecyclerView。这个state我们暂时不管,官方文档的说法就是:
RecyclerView.State: The current state of RecyclerView。
看其他的参数:
我迷茫的在于:这个画布canvas,具体指哪个地方呢?这个RecyclerView又要怎么用呢?
看参考文章的代码,其实蛮容易发现,canvas其实就和之前学习自定义View一样,指的就是整个画布。所以你需要的是获取每条分割线详细的位置。
而RecyclerView怎么用,它有一些方法是我们之前不需要用的,如parent.getChildCount() parent.getChildAt(i)等可以用来绘制。
我们很容易发现,因为它是一条线一条线绘制的,所以在特定的item处,可以使用特殊的绘制方法。比如设置一个标星区间。
public class MessageItemDecoration extends RecyclerView.ItemDecoration {
//设置分割线的高度
private int dividerHeight = 2;
//画笔
private Paint dividerPaint;
public MessageItemDecoration() {
dividerPaint = new Paint();
dividerPaint.setColor(Color.BLUE);
}
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
int childCount = parent.getChildCount();
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
for (int i = 0; i <= childCount - 1; i++) {
View view = parent.getChildAt(i);
float top = view.getBottom();
float bottom = view.getBottom() + dividerHeight;
c.drawRect(left, top, right, bottom, dividerPaint);
}
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0, 0, 0, dividerHeight);
}
}
代码如上,效果如下:
之后调整一下画线的位置,就可以实现一开始预期的效果了
三 后记 关于ItemDecoration装饰效果
本来想的是,分成几个组,不同组之间的距离不同。后来发现不大行,因为它的getItemOffsets是对所有子项的。不过我们可以考虑在头像旁边加一个星星来表示置顶,而非一定要设置成灰色背景什么的。
同样,或许这样也可以设置信息的效果。
这个如果有需要的话,之后再来做自定义分割线(二)