RecyclerView 之ItemDecoration分隔线
RecyclerView 之ItemDecoration悬浮分隔线
RecyclerView 之ItemDecoration分隔线+悬浮分隔线
实现RecyclerView的分隔线,则要继承于RecyclerView.ItemDecoration,如下图所示:

可以看出最主要的有三个方法:
(为易于分辨,设置RecyclerView背景色为绿色(#00cdcd),ItemView背景色为黄色(#cdcd00))
-
void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)
用以设置各个ItemView的内嵌偏移长度
当设置outRect.set(10, 20 , 30 , 40)
时:

当设置
outRect.left = 40
时:
那么,如果设置
outRect.top = 1
(分割线高度为1px),再配合RecyclerView的背景色,是不就可以实现分割线了呢?是的!但是这种方式过度依赖于RecyclerView的背景色,不够灵活,所以一般在onDraw中绘制分割线。

-
void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)
先于ItemView绘制, 所以绘制图层在ItemView以下,所以如果绘制区域与ItemView区域相重叠,会被遮挡。
(将RecyclerView背景色为白色(#FFFFFF),ItemView背景色为透明(不设置背景色),分隔线颜色为红色)
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
//获取RecyclerView的Child view的个数
int childCount = parent.getChildCount();
//遍历每个Item,分别获取它们的位置信息,然后再绘制对应的分割线
for (int i = 0; i < childCount; i++) {
View childView = parent.getChildAt(i);
//绘制分割线
c.drawRect(childView.getLeft(),
childView.getTop() - mDividerHeight,
childView.getRight(),
childView.getTop(),
mDividerPaint);
}
}

当然,在不同的需求中,对分隔线的要求也很多,比如:
- RecyclerView添加几个header或footer(当然RecyclerView中没有header、footer,大家都是ItemView,这里便于描述),而header和footer部分不要分隔线;
- 分隔线不要贯穿整个RecyclerView,左右可设置margin;
等等
附上完整代码抛砖引玉:
package com.test.wrapper.indexList;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class RecyclerItemDecoration extends RecyclerView.ItemDecoration {
/**
* RecyclerView 首部偏移量,前mOffsetStart个item不展示分隔线
*/
private int mOffsetStart = 0;
/**
* RecyclerView 尾部偏移量,后mOffsetEnd个item不展示分隔线
*/
private int mOffsetEnd = 0;
/**
* 分隔线 颜色、高度、左Margin、右Margin
*/
private Paint mDividerPaint;
private int mDividerColor = Color.parseColor("#cd0000");
private int mDividerHeight = 1;
private int mDividerLeftMargin = 0;
private int mDividerRightMargin = 0;
public RecyclerItemDecoration() {
this.mDividerPaint = new Paint();
//分隔线画笔
mDividerPaint.setColor(mDividerColor);
//抗锯齿
mDividerPaint.setAntiAlias(true);
//抗抖动
mDividerPaint.setDither(true);
}
/**
* 用以设置各个ItemView的内嵌偏移长度(inset)
*
* @param outRect Rect
* @param view View
* @param parent RecyclerView
* @param state RecyclerView.State
*/
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
//获取子View在RecyclerView中位置
int positionInRecycler = parent.getChildAdapterPosition(view);
//判断当前位置是否需要 分隔View 或 分隔线 或 悬浮分隔
if (isHasDivider(parent, positionInRecycler)) {
outRect.top = mDividerHeight;
}
}
/**
* 在子视图上设置绘制范围,并绘制内容
* 先于ItemView绘制, 所以绘制图层在ItemView以下,所以如果绘制区域与ItemView区域相重叠,会被遮挡
*
* @param c Canvas
* @param parent RecyclerView
* @param state RecyclerView.State
*/
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
//获取RecyclerView的Child view的个数
int childCount = parent.getChildCount();
//遍历每个Item,分别获取它们的位置信息,然后再绘制对应的分割线
for (int i = 0; i < childCount; i++) {
View childView = parent.getChildAt(i);
if (isHasDivider(parent, childView)) {
//绘制Divider宽度与ItemView宽度一致
drawDivider(c, childView.getLeft() + mDividerLeftMargin,
childView.getTop() - mDividerHeight,
childView.getRight() - mDividerRightMargin,
childView.getTop());
}
}
}
//绘制分隔线
private void drawDivider(Canvas c, float left, float top, float right, float bottom) {
// 通过Canvas绘制矩形(分割线)
c.drawRect(left, top, right, bottom, mDividerPaint);
}
//某个ItemView是否有分隔线
private boolean isHasDivider(RecyclerView parent, View childView) {
return isHasDivider(parent, parent.getChildAdapterPosition(childView));
}
/**
* 某位置是否有分隔线
* 子类可覆盖
*
* @param parent RecyclerView
* @param positionInRecycler RecyclerView中位置
* @return boolean
*/
protected boolean isHasDivider(RecyclerView parent, int positionInRecycler) {
if (positionInRecycler <= mOffsetStart) {
return false;
}
if (parent.getAdapter() != null) {
if (positionInRecycler > parent.getAdapter().getItemCount() - mOffsetEnd - mOffsetStart) {
return false;
}
}
return true;
}
}
使用:
每两个ItemView有一个分隔线(使用的RecyclerView有下拉刷新,相当于mOffsetStart = 1,故 (positionInRecycler - 1) ),分隔线左起30:
mRecyclerView.addItemDecoration(object : RecyclerItemDecoration() {
override fun isHasDivider(parent: RecyclerView?, positionInRecycler: Int): Boolean {
return (positionInRecycler - 1) % 2 == 0
}
})

over ~
分隔线就到此结束了,下一节一起来撸悬浮分隔线
RecyclerView 之ItemDecoration悬浮分隔线
欢迎大家多多留言交流哈 ·_·
网友评论