在平时开发中,一直没有用到 Android提供的ItemDecoration来设置分割线,不太熟悉用法,基本都是写在列表的ViewHolder里,后来翻了一下Google提供的这个ItemDecoration,感觉还是挺好用的,花点时间,记录一下使用方法。
使用到ItemDecoration,基本步骤
1.编写一个RecyclerView.ItemDecoration的子类,
2.重写getItemOffsets方法 和onDraw方法。
3.为RecyclerView添加一个ItemDecoration。
其中重点是第二条重写getItemOffsets和onDraw方法。
1.先来看getItemOffsets方法
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
}
先简单理解这个方法在itemview 上下左右偏移出多少的空间用来画分割线,等下看到具体效果就能明白。
这个偏移量怎么设置呢,就设置在第一个参数outRect里:
outRect.set(int left,int top,int right,int bottom);
这四个参数,分别代表了itmeview的 左,上,右,下的偏移量。
好了,这个时候推想一下,一个垂直方向的RecyclerView如果想在每个itemView的底部添加一个分割线,是不是就可以利用getItemOffsets方法,在itemView的底部偏移出一个空间来画分割线?
想法有了,可以试试,先在底部偏移出30px的空间。
先写一个RecyclerView ,代码如下
public class RecyClerViewLineActivity extends BaseActivity {
private RecyclerView mRecyclerView;
private NameAdapter mNameAdapter;
private LinearLayoutManager mLinearLayoutManager;
@Override
protected void initView() {
setContentView(R.layout.ac_recy);
mRecyclerView = (RecyclerView) findViewById(R.id.ac_recy_list_rcy);
mLinearLayoutManager = new LinearLayoutManager(this );
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mNameAdapter = new NameAdapter(this);
mRecyclerView.setAdapter(mNameAdapter);
CustomItemDecoration mItemDecoration=new CustomItemDecoration(this);
mRecyclerView.addItemDecoration(mItemDecoration);
}
}
public class CustomItemDecoration extends RecyclerView.ItemDecoration {
//利用系统属性中的listDivider来添加
public static final int[] ATRRS = new int[]{
android.R.attr.listDivider
};
private Context mContext;
private Drawable mDivder;
public CustomItemDecoration(Context mContext) {
this.mContext = mContext;
final TypedArray ta = mContext.obtainStyledAttributes(ATRRS);
this.mDivder = ta.getDrawable(0);
ta.recycle();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
//只在下面 偏移
outRect.set(0, 0, 0,30);
}
}
简单的一个RecyclerView,每个itemView 有个TextView.
比对后发现每个itemView底部多出了30px的空间 ,推测出来应该是修改的外边距,所以些分割线的时候,一定要算出精准的距离,否则会影响到写好的Ui效果。
另外可以测试一下 ,左右上下都修改的效果。
outRect.set(10,5,15,30);
2.知道了getItemOffsets方法后,看现在看一下onDraw方法
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
}
后面两个参数先不看,只看第一个,很明显是传入一个画布,需要我们来画图了。
接着刚才的需求,我们已经在itemView的下方偏移出了一个30px的高度,需要画一个20px的高度的分割线。
要画图,得有画布和坐标,画布是给我们了,坐标需要我们算出来。
结合需求,发现
1)分割线的left 是一定的,都等于容器的paddingleft。
2)分割线的right也是一定的,都等于容器的width- 容器的paddingRigth。
只剩下top和bottom了。
3)top等于每个itemView的bottom+ 每个itemView的marginBottom(因为是在底部)
4)bottom等于 刚刚算出来的top+分割线自身的高度。
好了 ,四个左边都给了可以画图了。
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
//垂直的列表的分割线 ,左边距是一样的,这里减去 父容器才paddingLeft
int left=parent.getPaddingLeft();
//同样,右边也是一样的
int right=parent.getWidth()-parent.getPaddingRight();
//获取child的count
int count=parent.getChildCount();
//循环 获得 top 和 bottom
for(int i=0;i<count;i++){
View child=parent.getChildAt(i);
RecyclerView.LayoutParams lyp =(RecyclerView.LayoutParams)child.getLayoutParams();
// 获取 child 的底边到父容器的距离,因为分割线在itme的下面,所以这个距离就变成了分割线的距离父容器的 top
int top=child.getBottom()+lyp.bottomMargin;
//top再加分割线的高度,等于bottom
int bottom=top+ 20; //这里个20是假设的
mDivder.setBounds(left,top,right,bottom);
mDivder.draw(c);
}
}
看效果
。
好到此,垂直方向的分割线已经完成了。
3.其实根据刚才的推测,横向的RecyclerView的分割线原理也很好推测。(还是以右边偏移30px,分割线20px为列)
1)首先是偏移方向,需要再itemView的右边 偏移个30px的空间。
2)分割线的top 是一定的,都等于容器的paddingTop。
3)分割线的bottom也是一定的,都等于容器的height- 容器的paddingBottom。
只剩下right和left了。
4)left等于每个itemView的right+ 每个itemView的marginRight(因为是在右边)
5)right等于 刚刚算出来的left+分割线自身的宽度。
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
//只在右边 偏移
outRect.set(0, 0, 30,0);
}
//在onDraw里调用
private void drawHorizontal(Canvas c, RecyclerView parent) {
//水平的列表的分割线 ,top是一定的
int top=parent.getPaddingTop();
//同样,bottom也是一定的
int bottom=parent.getHeight()-parent.getPaddingBottom();
//获取child的count
int count=parent.getChildCount();
//循环 获得 left 和 right
for(int i=0;i<count;i++){
View child=parent.getChildAt(i);
RecyclerView.LayoutParams lyp =(RecyclerView.LayoutParams)child.getLayoutParams();
// 获取 child 的右边到父容器的距离,因为分割线在itme的右边,所以这个距离就变成了分割线的距离父容器的 left
int left=child.getRight()+lyp.rightMargin;
//left再加分割线的宽度,等于right
int right=left+ 20px;
mDivder.setBounds(left,top,right,bottom);
mDivder.draw(c);
}
}
效果
以上就是在横向和纵向RecyclerView中添加分割线的做法,还可以写一个标识符,将纵向和横向分割符封装在同一个 ItemDecoration中,根据传入的不同值,来显示不同的效果。