1.简介
RecyclerView.ItemDecoration的作用是给ItemView添加装饰,绘制更多内容,增强itemUI的效果。例子:
1)绘制分割线
2) 数据分组等
2.使用方法:
ItemDecoration
类中仅有3个方法,具体如下:
public class TestDividerItemDecoration extends RecyclerView.ItemDecoration {
// 方法1:getItemOffsets()
// 作用:设置ItemView的内嵌偏移长度(inset)
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
...
}
// 方法2:onDraw()
// 作用:在子视图上设置绘制范围,并绘制内容
// 类似平时自定义View时写onDraw()一样
// 绘制图层在ItemView以下,所以如果绘制区域与ItemView区域相重叠,会被遮挡
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
...
}
// 方法3:onDrawOver()
// 作用:同样是绘制内容,但与onDraw()的区别是:绘制在图层的最上层
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
...
}
2.1 getItemOffsets()
1) 作用
设置ItemView的内嵌偏移长度(inset)
RecyclerView
中的 ItemView 外面会包裹着一个矩形(outRect
)outRect
)与 ItemView
的间隔outRect
中的 top、left、right、bottom
参数 控制2)使用
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
// 参数说明:
// 1. outRect:全为 0 的 Rect(包括着Item)
// 2. view:RecyclerView 中的 视图Item
// 3. parent:RecyclerView 本身
// 4. state:状态
outRect.set(50, 0, 0,50);
// 4个参数分别对应左(Left)、上(Top)、右(Right)、下(Bottom)
// 上述语句代表:左&下偏移长度=50px,右 & 上 偏移长度 = 0
...
}
结论:outRect4个属性值影响着ItemView的Padding值
具体过程:在RecyclerView进行子View宽高测量时(measureChild()),会将getItemOffsets()里设置的 outRect4个属性值(Top、Bottom、Left、Right)通过insert值累加 ,并最终添加到子View的 Padding属性中
2.2 onDraw
作用:通过 Canvas
对象绘制内容
使用:
@Override
public void onDraw(Canvas c, RecyclerView parent,
RecyclerView.State state) {
....
// 使用类似自定义View时的 onDraw()
}
注意:
注意点1:Itemdecoration
的onDraw()
绘制会先于ItemView
的onDraw()
绘制,所以如果在Itemdecoration
的onDraw()
中绘制的内容在ItemView
边界内,就会被ItemView
遮挡住。
解决方案:配合前面的 getItemOffsets()
一起使用在outRect
矩形 与 ItemView
的间隔区域 绘制内容
即:通过getItemOffsets()
设置与 Item
的间隔区域,从而获得与ItemView
不重叠的绘制区域
注意点2: getItemOffsets()
针对是每一个 ItemView
的,而 onDraw()
针对 RecyclerView
本身
解决方案:在 使用onDraw()
绘制时,需要先遍历RecyclerView
的所有ItemView
分别获取它们的位置信息,然后再绘制内容
RecyclerView
的ItemView
(即Child view
),并不是 Adapter
设置的每一个 item
,而是可见的 item
Item
才是RecyclerView
的 Child view
3.实例讲解: 绘制分割线
实例说明:在ItemView设计一个高度为 10 px 的红色分割线
思路 :
通过getItemOffsets()设置与 Item 的下间隔区域 = 10 px
设置好onDraw()可绘制的区域
通过onDraw()绘制一个高度 = 10px的矩形(填充颜色=红色)
步骤1:自定义ItemDecoration类
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Paint mPaint;
// 在构造函数里进行绘制的初始化,如画笔属性设置等
public DividerItemDecoration() {
mPaint = new Paint();
mPaint.setColor(Color.RED);
// 画笔颜色设置为红色
}
// 重写getItemOffsets()方法
// 作用:设置矩形OutRect 与 Item 的间隔区域
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int itemPosition = parent.getChildAdapterPosition(view);
// 获得每个Item的位置
// 第1个Item不绘制分割线
if (itemPosition != 0) {
outRect.set(0, 0, 0, 10);
// 设置间隔区域为10px,即onDraw()可绘制的区域为10px
}
}
// 重写onDraw()
// 作用:在间隔区域里绘制一个矩形,即分割线
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
// 获取RecyclerView的Child view的个数
int childCount = parent.getChildCount();
// 遍历每个Item,分别获取它们的位置信息,然后再绘制对应的分割线
for ( int i = 0; i < childCount; i++ ) {
// 获取每个Item的位置
final View child = parent.getChildAt(i);
int index = parent.getChildAdapterPosition(child);
// 第1个Item不需要绘制
if ( index == 0 ) {
continue;
}
// 获取布局参数
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
// 设置矩形(分割线)的宽度为10px
final int mDivider = 10;
// 根据子视图的位置 & 间隔区域,设置矩形(分割线)的2个顶点坐标(左上 & 右下)
// 矩形左上顶点 = (ItemView的左边界,ItemView的下边界)
// ItemView的左边界 = RecyclerView 的左边界 + paddingLeft距离 后的位置
final int left = parent.getPaddingLeft();
// ItemView的下边界:ItemView 的 bottom坐标 + 距离RecyclerView底部距离 +translationY
final int top = child.getBottom() + params.bottomMargin +
Math.round(ViewCompat.getTranslationY(child));
// 矩形右下顶点 = (ItemView的右边界,矩形的下边界)
// ItemView的右边界 = RecyclerView 的右边界减去 paddingRight 后的坐标位置
final int right = parent.getWidth() - parent.getPaddingRight();
// 绘制分割线的下边界 = ItemView的下边界+分割线的高度
final int bottom = top + mDivider;
// 通过Canvas绘制矩形(分割线)
c.drawRect(left,top,right,bottom,mPaint);
}
}
}
2.3 onDrawOver()
onDraw()
类似,都是绘制内容onDraw()
的区别是:Itemdecoration
的onDrawOver()
绘制 是后于 ItemView
的onDraw()
绘制即不需要考虑绘制内容被ItemView遮挡的问题,反而 ItemView会被onDrawOver()绘制的内容遮挡
绘制时机比较:
Itemdecoration.onDraw()> ItemView.onDraw() > Itemdecoration.onDrawOver()
如图: