在平時開發中,一直沒有用到 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中,根據傳入的不同值,來顯示不同的效果。