想到分割線,原先一直是在item的佈局中直接加入,在adapter中進行判斷,如果最後一個子項則將分割線隱藏,感受過小兒科了,今天來好好研究這個ItemDecoration的使用。java
文章參考自RecyclerView 之 ItemDecoration 講解及高級特性實踐,寫的很詳細,仔細看後就會用了,我只是在此基礎上增添了能夠更改顏色、寬度、左右偏移的功能。廢話很少說,我們開始作吧。git
1、創建工程,建立Adapter,加載佈局文件github
public class MainActivity extends AppCompatActivity {
@BindView(R.id.recyclerview)
RecyclerView recyclerview;
private List<String> dataList; //數據項
private MyAdapter myAdapter; //適配器
@Override
protected void onCreate(Bundle savedInstanceState) {
...
initData();
myAdapter = new MyAdapter(R.layout.item_recyclerview,dataList);
recyclerview.setAdapter(myAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerview.setLayoutManager(layoutManager);
}
private void initData(){
dataList = new ArrayList<>();
for(int i = 0;i<20;i++){
dataList.add("子項"+i);
}
}
}
複製代碼
public class MyAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
public MyAdapter(int layoutResId, List<String> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, String item) {
helper.setText(R.id.tv_content, item);
}
}
複製代碼
2、創建分割器ide
提早說明,如下內容均是在每一個ItemView的頂部加入分割線,第一個不加工具
經過recyclerview.addItemDecoration(new SimpleItemDecoration());
將如下分割器加入到RecyclerView中便可佈局
public class SimpleItemDecoration extends RecyclerView.ItemDecoration {
/** * @param outRect 全爲0的rect,用來指定偏移區域 * @param view 指RecyclerView中的Item * @param parent 指RecyclerView自己 * @param state 狀態 */
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (parent.getChildAdapterPosition(view) != 0) {
//直接設置爲1px
outRect.top = 1;
}
}
}
複製代碼
加入後的效果: ui
以上方法,經過使每一個ItemView向上撐出1px距離,而RecyclerView背景爲灰色,這樣就顯示出1px的灰色線,實現分割線功能,看到這你可能會想,這也太粗糙了,若是我想要改變分割線的寬度、顏色該怎麼辦,總不能每寫一個RecyclerView都再寫一套分割器,更改RecyclerView背景顏色吧,並且通常分割線並不佔滿所有寬度,有左右偏移,那該怎麼實現呢?this
別急,咱們先了解下getItemOffsets()方法中的outRect這個參數。spa
其中的藍色部分爲咱們的RecyclerView的子項ItemView,外部黃色部分爲outRect,只是黃色,並不包含ItemView壓的那部分,left,right,top,bottom四個參數其實就是距離itemView的四個方向的偏移量,是指偏移 ItemView 各個方向的數值,在上面的例子中,咱們設置了outRect.top=1
,因此每一個ItemView之間有1px的空隙,因此呈現出1px灰色的分割線,分割線顏色決定於RecyclerView的背景色。.net
1、設置高度:
既然知道了這四個參數表明相對itemview的偏移,那麼分割線的高度就好辦了。
如圖,想要紅色那樣高度的分割線,只須要outRect.top等於該高度就能夠了。咱們將該高度定義爲mDividerHeight
2、設置顏色、左右偏移:
高度有了,若是咱們只想繪製紅色那部分矩形而不是ItemView上方的所有該怎麼辦?咱們知道每個View中的onDraw()方法是用來繪製組件的UI效果,因此想要顏色的話,須要咱們重寫ItemDecoration中的onDraw()方法。
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state);
複製代碼
能夠看到onDraw()方法中有參數Canvas,經過它來繪製紅色矩形,因此咱們須要知道該矩形的四條邊的位置。
float dividerTop = view.getTop() - mDividerHeight; //矩形頂部
float dividerBottom = view.getTop(); //矩形底部
float dividerLeft = parent.getPaddingLeft() + margin; //矩形左側
float dividerRight = parent.getWidth() - parent.getPaddingRight() - margin; //矩形右側
複製代碼
矩形頂部=itemview的頂部加上分割線的高度,咦?我怎麼寫的減號?看下圖你應該就會明白
安卓中座標是這樣的,向下向右爲正,因此紅色矩形頂部位置就應該是itemView的top位置-矩形高度
偏移的話左側加上偏移量,右側減去偏移量便可。
c.drawRect(dividerLeft, dividerTop, dividerRight, dividerBottom, mPaint);
複製代碼
這樣咱們要繪製的矩形就出來了,等等,咱們只是畫了個矩形,還沒顏色呢,再來看看drawRect()中的參數,咱們還缺一個mPaint畫筆,經過它來設置矩形分割線顏色。
public MyDecoration() {
mPaint = new Paint();
mPaint.setAntiAlias(true); //抗鋸齒
mPaint.setColor(Color.GRAY); //默認灰色
}
複製代碼
經過以上步驟,帶有顏色和偏移量,且具備必定高度的分割線就畫好了,其實還沒完,須要注意:getItemOffsets 是針對每個 ItemView,而 onDraw 方法倒是針對 RecyclerView 自己,因此在 onDraw 方法中須要遍歷屏幕上可見的 ItemView,分別獲取它們的位置信息,而後分別的繪製對應的分割線。
代碼以下:
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
int childCount = parent.getChildCount(); //可見ItemView個數
//由於getItemOffsets是針對每個ItemView,而onDraw方法是針對RecyclerView自己,因此須要循環遍從來設置
for (int i = 0; i < childCount; i++) {
View view = parent.getChildAt(i);
int index = parent.getChildAdapterPosition(view);
//第一個ItemView不須要繪製
if (index == 0) {
continue;//跳過本次循環體中還沒有執行的語句,當即進行下一次的循環條件判斷
}
float dividerTop = view.getTop() - mDividerHeight; //矩形頂部
float dividerLeft = parent.getPaddingLeft() + margin; //矩形左側
float dividerBottom = view.getTop(); //矩形底部
float dividerRight = parent.getWidth() - parent.getPaddingRight() - margin;//矩形右側
c.drawRect(dividerLeft, dividerTop, dividerRight, dividerBottom, mPaint);
}
}
複製代碼
在實際運用中,咱們的分割線顏色高度等樣式可能不同,這裏咱們經過建造者模式來設置這些屬性
//設置左右偏移(默認是設置的同樣的,若須要本身更改)
public MyDecoration setMargin(float margin) {
this.margin = margin;
return this;
}
//設置顏色
public MyDecoration setColor(int color) {
mPaint.setColor(color);
return this;
}
//設置分割線高度
public MyDecoration setDividerHeight(float height) {
this.mDividerHeight = height;
return this;
}
複製代碼
這樣咱們就完成了分割線的自定義
完整代碼以下:
public class MyDecoration extends RecyclerView.ItemDecoration {
private float mDividerHeight = 1; //線的高度
private Paint mPaint; //畫筆將本身作出來的分割線矩形畫出顏色
private float margin = 0; //左右偏移量
public MyDecoration() {
mPaint = new Paint();
mPaint.setAntiAlias(true); //抗鋸齒
mPaint.setColor(Color.GRAY); //默認顏色
}
//經過建造者模式來設置三個屬性
//設置左右偏移(默認是設置的同樣的,若須要本身更改)
public MyDecoration setMargin(float margin) {
this.margin = margin;
return this;
}
//設置顏色
public MyDecoration setColor(int color) {
mPaint.setColor(color);
return this;
}
//設置分割線高度
public MyDecoration setDividerHeight(float height) {
this.mDividerHeight = height;
return this;
}
//在這裏就已經把寬度的偏移給作好了
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
//第一個ItemView不須要在上面繪製分割線
if (parent.getChildAdapterPosition(view) != 0) {
outRect.top = (int) mDividerHeight;//指相對itemView頂部的偏移量
}
}
//這裏主要是繪製顏色的
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
int childCount = parent.getChildCount();
//由於getItemOffsets是針對每個ItemView,而onDraw方法是針對RecyclerView自己,因此須要循環遍從來設置
for (int i = 0; i < childCount; i++) {
View view = parent.getChildAt(i);
int index = parent.getChildAdapterPosition(view);
//第一個ItemView不須要繪製
if (index == 0) {
continue;//跳過本次循環體中還沒有執行的語句,當即進行下一次的循環條件判斷
}
float dividerTop = view.getTop() - mDividerHeight;
float dividerLeft = parent.getPaddingLeft() + margin;
float dividerBottom = view.getTop();
float dividerRight = parent.getWidth() - parent.getPaddingRight() - margin;
c.drawRect(dividerLeft, dividerTop, dividerRight, dividerBottom, mPaint);
}
}
}
複製代碼
使用:
MyDecoration myDecoration = new MyDecoration();
myDecoration.setColor(ContextCompat.getColor(getContext(),R.color.line_gray)).setMargin(ConvertUtils.dp2px(getContext(), 15)).setDividerHeight(ConvertUtils.dp2px(getContext(),1));
recyclerView.addItemDecoration(myDecoration);
複製代碼
實際使用中咱們是dp單位,因此這裏我使用了ConvertUtils工具類,將dp轉爲px
代碼以下:
public static int dp2px(Context context, final float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
複製代碼
看下效果:
到這裏咱們想要的功能就所有完成了。(終於碼完了開心!)
若是咱們的RecyclerView是橫向的滑動,原理相似,剩下的就交給大家了(懶得寫了嘿嘿)
一共兩步:
一、經過getItemOffsets()在itemView頂部撐出來一片區域
二、經過onDraw()方法來在該區域內繪製想要顏色及偏移量的分割線
其實ItemDecoration還有不少很牛逼的地方,例如實現時光軸效果,排行榜的角標,能夠看看我參考的那篇文章的實現,寫得很詳細的,是真大佬!往後Demo寫出來了再來更新