前言
在开发的时候,如果你用到的是RecycleView
,就常常会有下划线的视觉。平时我们就直接在item视觉里就加上了上划线,但今天用了ItemDecoration
类,会更快速地实现我们的表现效果。
使用
在自定义ItemDecoration通常要复写其3个方法
public class DividerItemDecoration 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) {
.....
}
getItemOffsets()
像图片所看到RecycleView外面会包裹一层矩形,而
outRect
的与ItemVIeww的间隔则是由outRect
中的top
、left
、right
、bottom
参数 控制
onDraw()
有两个注意的地方
Itemdecoration
的onDraw()
绘制会先于ItemView
的onDraw()
绘制,getItemOffsets()
针对是每一个ItemView
的,而onDraw()
针对 RecyclerView 本身
@Override
public void onDraw(Canvas c, RecyclerView parent,
RecyclerView.State state) {
// RecyclerView 的左边界加上 paddingLeft距离 后的坐标位置
final int left = parent.getPaddingLeft();
// RecyclerView 的右边界减去 paddingRight 后的坐标位置
final int right = parent.getWidth() - parent.getPaddingRight();
// 即左右边界就是 RecyclerView 的 ItemView区域
// 获取RecyclerView的Child view的个数
final int childCount = parent.getChildCount();
// 设置布局参数
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
// 遍历每个RecyclerView的Child view
// 分别获取它们的位置信息,然后再绘制内容
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
int index = parent.getChildAdapterPosition(view);
// 第一个Item不需要绘制
if ( index == 0 ) {
continue;
}
// ItemView的下边界:ItemView 的 bottom坐标 + 距离RecyclerView底部距离 +translationY
final int top = child.getBottom() + params.bottomMargin +
Math.round(ViewCompat.getTranslationY(child));
// 绘制分割线的下边界 = ItemView的下边界+分割线的高度
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
此处遍历的RecyclerView的ItemView(即Child view),并不是 Adapter 设置的每一个 item,而是可见的 item
onDrawOver()
Itemdecoration的onDrawOver()绘制 是后于 ItemView的onDraw()绘制
举个栗子
了解完ItemDecoration的基本知识后,开始写个时间轴效果
代码中主要的类DividerItemDecoration
的实现
public class DividerItemDecoration extends RecyclerView.ItemDecoration{
int item_top;
int item_left;
private Paint mPaint1;
private Paint mPaint2;
private Paint mPaint3;
// 轴点半径
private int circle_radius;
public DividerItemDecoration() {
mPaint1 = new Paint();
mPaint2 = new Paint();
mPaint3= new Paint();
mPaint1.setStrokeWidth(4f);
mPaint2.setStrokeWidth(4f);
mPaint1.setColor(Color.RED);
mPaint2.setColor(Color.BLUE);
mPaint3.setColor(Color.BLUE);
mPaint3.setTextSize(30);
item_top = 50;
item_left = 200;
circle_radius = 12;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
int itemPosition = parent.getChildAdapterPosition(view);
outRect.set(item_left, item_top, 0 ,0 );
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
//获取RecycleView的可见Child view 的个数
int childCount = parent.getChildCount();
//遍历每个item
for (int i = 0; i < childCount; i++){
View child = parent.getChildAt(i);
int index = parent.getChildAdapterPosition(child);
//圆心位置
float circle_y = child.getTop() - item_top + (item_top + child.getHeight()) / 2;
float circle_x = child.getLeft() - item_left/3;
/**
*这里除了圆形,可以定义自己想要实现的效果
*绘制时间轴空心圆点
* mPaint.setStyle(Paint.Style.STROKE);
* c.drawCircle(centerX,centerY,mNodeRadius,mPaint);
* mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
*/
c.drawCircle(circle_x, circle_y, circle_radius, mPaint1);
//上半轴
float upLine_top_x = circle_x;
float upLine_top_y = child.getTop() - item_top;
float upLine_bottom_x = circle_x;
float upLine_bottom_y = circle_y - circle_radius / 2;
//第一个ItemView不需要在上面绘制竖线
if (index != 0)
c.drawLine(upLine_top_x, upLine_top_y, upLine_bottom_x, upLine_bottom_y, mPaint1);
//下半轴
float bottomLine_top_x = circle_x;
float bottomLine_top_y = circle_y + circle_radius / 2;
float bottomLine_bottom_x = circle_x;
float bottomLine_bottom_y = child.getTop() + child.getHeight();
if (index != childCount - 1)
c.drawLine(bottomLine_top_x, bottomLine_top_y, bottomLine_bottom_x, bottomLine_bottom_y, mPaint2);
//设置文本
float text_x = child.getLeft() - item_left * 5/6;
float text_y = upLine_bottom_y;
c.drawText("哈哈哈", text_x, text_y, mPaint3);
c.drawText("2017.4.03", text_x + 5, text_y + 20, mPaint2);
}
}
}
之后绑定在Recycleview
就可以显示出效果了
// 绑定数据到RecyclerView
public void initView(){
Rv = (RecyclerView) findViewById(R.id.my_recycler_view);
//使用线性布局
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
Rv.setLayoutManager(layoutManager);
Rv.setHasFixedSize(true);
//用自定义分割线类设置分割线
Rv.addItemDecoration(new DividerItemDecoration());
//为ListView绑定适配器
myAdapter = new DividerAdapter(this,listItem);
Rv.setAdapter(myAdapter);
}
然后效果如下图:
现在可以开心的去自己定义ItemDecoration
参考: 教你玩转 Android RecyclerView:深入解析 RecyclerView.ItemDecoration类