ItemDecoration是recyclerView的静态内部类,主要是为RecyclerView的Item绘制各种特效,添加效果,最常用的就是绘制分割线
ItemDecoration只有三个常用方法,一个是getItemOffsets设置偏离值,一个ondraw绘制,还有一个ondrawOver主要是浮层绘制
public abstract static class ItemDecoration {
/**
* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
* Any content drawn by this method will be drawn before the item views are drawn,
* and will thus appear underneath the views.
*
* @param c Canvas to draw into
* @param parent RecyclerView this ItemDecoration is drawing into
* @param state The current state of RecyclerView
*/
public void onDraw(Canvas c, RecyclerView parent, State state) {
onDraw(c, parent);
}
/**
* @deprecated
* Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)}
*/
@Deprecated
public void onDraw(Canvas c, RecyclerView parent) {
}
/**
* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
* Any content drawn by this method will be drawn after the item views are drawn
* and will thus appear over the views.
*
* @param c Canvas to draw into
* @param parent RecyclerView this ItemDecoration is drawing into
* @param state The current state of RecyclerView.
*/
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
onDrawOver(c, parent);
}
/**
* @deprecated
* Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)}
*/
@Deprecated
public void onDrawOver(Canvas c, RecyclerView parent) {
}
/**
* @deprecated
* Use {@link #getItemOffsets(Rect, View, RecyclerView, State)}
*/
@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}
/**
* Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
* the number of pixels that the item view should be inset by, similar to padding or margin.
* The default implementation sets the bounds of outRect to 0 and returns.
*
* <p>
* If this ItemDecoration does not affect the positioning of item views, it should set
* all four fields of <code>outRect</code> (left, top, right, bottom) to zero
* before returning.
*
* <p>
* If you need to access Adapter for additional data, you can call
* {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
* View.
*
* @param outRect Rect to receive the output.
* @param view The child view to decorate
* @param parent RecyclerView this ItemDecoration is decorating
* @param state The current state of RecyclerView.
*/
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
parent);
}
}
getItemOffsets方法是在四个方向设置偏移值
/**1. outRect:全为 0 的 Rect(包括着Item)
* 2. view:RecyclerView 中的 视图Item
* 3. parent:RecyclerView 本身
* 4. state:状态
* /
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
// 4个参数分别对应左(Left)、上(Top)、右(Right)、下(Bottom)
// 上述语句代表:左和下偏移长度=50px,右 和 上 偏移长度 = 0
outRect.set(50, 0, 0,50);
}
自定义recyclerView的itemDecoration只要需要继承这个类即可,其余部分就和绘制自定义控件的方式一样
1,自定义分割线
class LineItemDecoration : RecyclerView.ItemDecoration() {
private val mPaint=Paint()
// 设置矩形(分割线)的宽度为1px
val mDivider = 1
// 在构造函数里进行绘制的初始化,如画笔属性设置等
init {
mPaint.color = Color.GRAY
}
// 重写getItemOffsets()方法
// 作用:设置矩形OutRect 与 Item 的间隔区域
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
super.getItemOffsets(outRect, view, parent, state)
outRect.set(0,0,0,1)
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State?) {
super.onDraw(c, parent, state)
// 获取RecyclerView的Child view的个数
val childCount = parent.childCount
// 遍历每个Item,分别获取它们的位置信息,然后再绘制对应的分割线
for (i in 0 until childCount) {
// 获取每个Item的位置
val child = parent.getChildAt(i)
val index = parent.getChildAdapterPosition(child)
// 获取布局参数
val params = child.layoutParams as RecyclerView.LayoutParams
// 矩形左上顶点 = (ItemView的左边界,ItemView的下边界)
// ItemView的左边界 = RecyclerView 的左边界 = paddingLeft距离 后的位置
val left = parent.paddingLeft
// ItemView的下边界:ItemView 的 bottom坐标 + 距离RecyclerView底部距离 +translationY
val top = child.bottom + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child))
// 矩形右下顶点 = (ItemView的右边界,矩形的下边界)
// ItemView的右边界 = RecyclerView 的右边界减去 paddingRight 后的坐标位置
val right = parent.width - parent.paddingRight
// 绘制分割线的下边界 = ItemView的下边界+分割线的高度
val bottom = top + mDivider
// 通过Canvas绘制矩形(分割线)
c.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), mPaint)
}
}
}
2,自定义时间轴
class DividerItemDecoration(val timeData: ArrayList<String>)// 在构造函数里进行绘制的初始化,如画笔属性设置等
: RecyclerView.ItemDecoration() {
// 写右边字的画笔(具体信息)
private val mPaint: Paint
// 写左边日期字的画笔( 时间 )
private val mPaint1: Paint
// 左 上偏移长度
private val itemView_leftinterval: Int
// 图标
private var mIcon: Bitmap? = null
init {
// 轴点画笔(红色)
mPaint = Paint()
mPaint.color = Color.BLUE
// 左边时间文本画笔(蓝色)
// 此处设置了两只分别设置 时分 & 年月
mPaint1 = Paint()
mPaint1.color = Color.BLUE
mPaint1.textSize = 25f
// 赋值ItemView的左偏移长度为200
itemView_leftinterval = 200
// 获取图标资源
mIcon = BitmapFactory.decodeResource(BaseApplication.mContext.getResources(), R.drawable.car);
}
// 重写getItemOffsets()方法
// 作用:设置ItemView 左 & 上偏移长度
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State?) {
super.getItemOffsets(outRect, view, parent, state)
// 设置ItemView的左 & 上偏移长度分别为200 px & 50px,即此为onDraw()可绘制的区域
outRect.set(itemView_leftinterval, 0, 0, 0)
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State?) {
super.onDraw(c, parent, state)
val childCount = parent.childCount
// 遍历每个Item,分别获取它们的位置信息,然后再绘制对应的分割线
for (i in 0 until childCount) {
// 获取每个Item对象
val child = parent.getChildAt(i)
Logger.e("position =" + i)
/**
* 绘制轴点
*/
// 轴点 = 圆 = 圆心(x,y)
val centerx = (child.left - itemView_leftinterval / 3).toFloat()
val centery = (child.top + child.height / 2).toFloat()
// 通过Canvas绘制角标
val width = mIcon?.width;
val height = mIcon?.height;
c.drawBitmap(mIcon, centerx - width!! / 4, centery - height!! / 2, mPaint);
val upLine_up_y = child.top.toFloat()
// 下端点坐标(x,y)
val upLine_bottom_y = centery
//绘制上半部轴线
c.drawLine(centerx, upLine_up_y, centerx, upLine_bottom_y - height / 3, mPaint)
val bottom_up_y = centery + height / 3
// 下端点坐标(x,y)
val bottomLine_bottom_y = child.bottom.toFloat()
//绘制下半部轴线
c.drawLine(centerx, bottom_up_y, centerx, bottomLine_bottom_y, mPaint)
// 获取每个Item的位置
val index = parent.getChildAdapterPosition(child)
// 设置文本起始坐标
val Text_x = (child.left - itemView_leftinterval).toFloat()
/**
* 绘制左边时间文本
*/
c.drawText(timeData.get(index), Text_x + itemView_leftinterval * 1f / 10, upLine_bottom_y - dp2px(BaseApplication.mContext, 10f), mPaint1)
}
}
}