RecyclerView 添加分割線

在平時開發中,一直沒有用到 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.

沒有分割線的運行效果
底部偏移了30px的效果

比對后發現每個itemView底部多出了30px的空間 ,推測出來應該是修改的外邊距,所以些分割線的時候,一定要算出精準的距離,否則會影響到寫好的Ui效果。
另外可以測試一下 ,左右上下都修改的效果。

outRect.set(10,5,15,30);
修改的偏移量為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);
        }


    }

看效果

30px的偏移和20px的分割線

好到此,垂直方向的分割線已經完成了。

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);
        }



    }

效果

橫向偏移30分割線20

以上就是在橫向和縱向RecyclerView中添加分割線的做法,還可以寫一個標識符,將縱向和橫向分割符封裝在同一個 ItemDecoration中,根據傳入的不同值,來顯示不同的效果。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容