原创内容,转载请注明出处:https://www.jianshu.com/p/e971d1224074
RecyclerView的简单介绍
关于RecyclerView,众所周知是谷歌新推出的一个强大的滑动组件,它的出现替代了经典的ListView、GridView,高度的解耦、异常的灵活性使之可以轻松实现listview、gridview、瀑布流等效果,包括淘宝等应用首页复杂布局的实现,也是利用了RecyclerView强大的扩展性。
RecyclerView分隔线
但是我们使用过程中发现,RecyclerView不可以像ListView那样,直接在布局文件里设置divider属性来添加分隔线。网上也有很多博客介绍自定义ItemDecoration实现简单的添加分隔线,个人觉得扩展性不强,索性自己定义了一个,目前支持设置分隔线宽度、颜色、左右间距、最后一条item是否显示分隔等,话不多说,先来波效果:
实现自定义ItemDecortation主要通过继承RecyclerView.ItemDecoration,重新绘制divider,具体代码如下:
/**
* 描述: 自定义线性ItemDecoration
* 作者: LemZ
*/
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private boolean mShowLastLine;
private int mSpanSpace = 2;
private int mLeftPadding;
private int mRightPadding;
public LinearItemDecoration(int span,int leftPadding,int rightPadding,int color,boolean show){
mSpanSpace = span;
mShowLastLine = show;
mLeftPadding = leftPadding;
mRightPadding = rightPadding;
mDivider = new ColorDrawable(color);
}
@Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int count = mShowLastLine ? parent.getAdapter().getItemCount() : parent.getAdapter().getItemCount() - 1;
if (isVertical(parent)) {
if (parent.getChildAdapterPosition(view) < count) {
outRect.set(0, 0, 0, mSpanSpace);
} else {
outRect.set(0, 0, 0, 0);
}
} else {
if (parent.getChildAdapterPosition(view) < count) {
outRect.set(0, 0, mSpanSpace, 0);
} else {
outRect.set(0, 0, 0, 0);
}
}
}
private boolean isVertical(RecyclerView parent) {
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof LinearLayoutManager) {
int orientation = ((LinearLayoutManager) layoutManager) .getOrientation();
return orientation == LinearLayoutManager.VERTICAL;
}
return false;
}
@Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (isVertical(parent)) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
private void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft() + mLeftPadding;
final int right = parent.getWidth() - parent.getPaddingRight() - mRightPadding;
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams();
final int top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
final int bottom = top + mSpanSpace; int count = mShowLastLine ? parent.getAdapter().getItemCount() : parent.getAdapter().getItemCount() - 1;
if (i < count) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
} else {
mDivider.setBounds(left, top, right, top);
mDivider.draw(c);
}
}
}
private void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams();
final int left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));
final int right = left + mSpanSpace; int count = mShowLastLine ? parent.getAdapter().getItemCount() : parent.getAdapter().getItemCount() - 1;
if (i < count) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
}
/**
* Builder模式
* */
public static class Builder{
private Context mContext;
private Resources mResources;
private int mSpanSpace;
private boolean mShowLastLine;
private int mLeftPadding;
private int mRightPadding;
private int mColor;
public Builder(Context context){
mContext = context;
mResources = context.getResources();
mSpanSpace = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 1f, context.getResources().getDisplayMetrics());
mLeftPadding = 0;
mRightPadding = 0;
mShowLastLine = false;
mColor = Color.BLACK;
}
/**
* 设置分割线宽(高)度
*/
public Builder setSpan(float pixels) {
mSpanSpace = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, pixels, mResources.getDisplayMetrics());
return this;
}
/**
* 设置分割线宽(高)度
*/
public Builder setSpan(@DimenRes int resource) {
mSpanSpace = mResources.getDimensionPixelSize(resource);
return this;
}
/**
* 设置左右间距
*/
public Builder setPadding(float pixels) {
setLeftPadding(pixels);
setRightPadding(pixels);
return this;
}
/**
* 设置左右间距
*/
public Builder setPadding(@DimenRes int resource) {
setLeftPadding(resource);
setRightPadding(resource);
return this;
}
/**
* 设置左间距
*/
public Builder setLeftPadding(float pixelPadding) {
mLeftPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, pixelPadding, mResources.getDisplayMetrics());
return this;
}
/**
* 设置右间距
*/
public Builder setRightPadding(float pixelPadding) {
mRightPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, pixelPadding, mResources.getDisplayMetrics());
return this;
}
/**
* 通过资源id设置左间距
*/
public Builder setLeftPadding(@DimenRes int resource) {
mLeftPadding = mResources.getDimensionPixelSize(resource);
return this;
}
/**
* 通过资源id设置右间距
*/
public Builder setRightPadding(@DimenRes int resource) {
mRightPadding = mResources.getDimensionPixelSize(resource);
return this;
}
/**
* 通过资源id设置颜色
*/
public Builder setColorResource(@ColorRes int resource) {
setColor(ContextCompat.getColor(mContext,resource));
return this;
}
/**
* 设置颜色
*/
public Builder setColor(@ColorInt int color) {
mColor = color;
return this;
}
/**
* 是否最后一条显示分割线
* */
public Builder setShowLastLine(boolean show){
mShowLastLine = show;
return this;
}
/**
* Instantiates a LinearItemDecoration with the specified parameters.
* @return a properly initialized LinearItemDecoration instance
*/
public LinearItemDecoration build() {
return new LinearItemDecoration(mSpanSpace,mLeftPadding,mRightPadding,mColor,mShowLastLine);
}
}
}
只有100多行代码,注释清晰,简单易读,Builder模式构造方便使用,这个类目前只支持LinearLayoutManager,包括VERTICAL和HORIZONTAL,主要方法包括:
getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)
onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
getItemOffsets主要是为每个item去计算出偏移空间来绘制divider,而onDraw用来去绘制具体的divider,代码里面通过判断LinearLayoutManager的垂直和水平来进行偏移,纵向列表绘制时要考虑测量分隔线距离左右的距离,实现对分隔线的多样化需求
通过builder设置你想要的效果,包括颜色、间距等,具体使用代码如下:
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
/**设置recyclerview*/
LinearItemDecoration divider = new LinearItemDecoration.Builder(context)
.setSpan(20f)
// .setPadding(R.dimen.line_width)
// .setLeftPadding(R.dimen.common_title_height)
// .setRightPadding(R.dimen.common_title_height)
.setColorResource(R.color.gray_line)
.setShowLastLine(true)
.build();
recycle_recommend.addItemDecoration(divider);
recycle_recommend.setLayoutManager(linearLayoutManager);
LinearLayoutManager的ItemDecoration添加就到这里,有好的建议欢迎留言,下一篇文章RecyclerView添加网格分隔线我将继续完善GridLayoutManager分隔线的添加,以及更深入地去分析其实现原理 ^ ^