RecycleView自定義ItemDecoration,實現時間軸效果
最近進行知識點掃盲,關於RecycleView的進行整理,自定義ItemDecoration,實現時間軸效果,先上圖:
此文參考了Carson_Ho的部落格:http://www.jianshu.com/p/9a796bb23a47,在此特別感謝,感覺怎麼寫都沒有大神寫的好,但是還要自己記錄一下,嘿嘿。
時間軸是通過自定義ItemDecoration實現的,接下來我們分析一下ItemDecoration其內部的方法,
一、getItemOffsets
作用:設定ItemView的內嵌的偏移長度
其實在ItemView外部包含一層矩形,該方法就是決定其left,top,right,bottom的長度,完整方法如下:
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
// 引數說明:
// 1. outRect:全為 0 的 Rect(包括著Item)
// 2. view:RecyclerView 中的 檢視Item
// 3. parent:RecyclerView 本身
// 4. state:狀態
outRect.set(50, 0, 0,50);
// 4個引數分別對應左(Left)、上(Top)、右(Right)、下(Bottom)
// 上述語句代表:左&下偏移長度=50px,右 & 上 偏移長度 = 0
//具體過程:在RecyclerView進行子View寬高測量時(measureChild()),
// 會將getItemOffsets()裡設定的 outRect4個屬性值(Top、Bottom、Left、Right)通過insert值累加 ,並最終新增到子View的 Padding屬性中
}
二、onDraw
作用:顧名思義,用來繪製的,類似view的ondraw()方法,此處注意的是當ItemDecoration的ondraw與child view有重疊的區域,最終會顯示child的檢視,因為ItemDecoration先繪製子的itemView後繪製,此現象稱為onDraw()的 OverDraw。此方法一般配合上面的getItemOffsets,先給預留出空間,然後在此空間進行繪製,完整方法如下:
//引數說明
// 1、c 畫布
//2、parent Recycle本身
//3、state 狀態
//通過此方法我們可以繪製想要繪製的圖案、圖片等
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
}
三、onDrawOver
作用:與上面的onDraw方法類似,唯一不同的是當ItemDecoration的ondraw與child view有重疊的區域,最終會顯示ItemDecoration的ondrawOver繪製的檢視,完整方法如下:
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
}
四、思路分析
通過上面的幾個方法我們完全可以自定義任何分割線了,然後分析時光軸,如下(借鑑):
1、首先設定便宜長度,預留空間,
2、繪製時光軸
3、繪製時間文字,下面分別實現
1、首先設定偏移長度,預留空間,如下
//首先通過getItemOffsets方法設定相應的偏移量
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
// 設定ItemView的左 & 上偏移長度分別為200 px & 50px,即此為onDraw()可繪製的區域
outRect.set(itemView_leftinterval, itemView_topinterval, 0, 0);
}
2、繪製時光軸及文字都在onDraw()內實現,如下:
// 重寫onDraw()
// 作用:在間隔區域裡繪製時光軸線 & 時間文字
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
//獲取子view的數量
int count =parent.getChildCount();
//迴圈遍歷,分別獲取它們的位置資訊,然後再繪製對應的分割線
for (int i = 0; i <count ; i++) {
// 獲取每個Item物件
View child = parent.getChildAt(i);
/**
* 繪製圖標
*/
//自定義設定圖示位置
float centerx = child.getLeft() - itemView_leftinterval / 3;
float centery = child.getTop() - itemView_topinterval + (itemView_topinterval + child.getHeight()) / 2;
// 通過Canvas繪製角標
c.drawBitmap(mIcon,centerx - circle_radius ,centery - circle_radius,mPaint);
/**
* 繪製上半軸線
*/
// 上端點座標(x,y)
float upLine_up_x = centerx+circle_radius;
float upLine_up_y = child.getTop() - itemView_topinterval;
// 下端點座標(x,y)
float upLine_bottom_x = centerx+circle_radius;
float upLine_bottom_y = centery - circle_radius;
//繪製上半部軸線
c.drawLine(upLine_up_x, upLine_up_y, upLine_bottom_x, upLine_bottom_y, mPaint);
/**
* 繪製下半軸線
*/
// 上端點座標(x,y)
float bottomLine_up_x = centerx+circle_radius;
float bottom_up_y = centery + circle_radius;
// 下端點座標(x,y)
float bottomLine_bottom_x = centerx+circle_radius;
float bottomLine_bottom_y = child.getBottom();
//繪製下半部軸線
c.drawLine(bottomLine_up_x, bottom_up_y, bottomLine_bottom_x, bottomLine_bottom_y, mPaint);
/**
* 繪製左邊時間文字
*/
// 獲取每個Item的位置
int index = parent.getChildAdapterPosition(child);
// 設定文字起始座標
float Text_x = child.getLeft() - itemView_leftinterval * 5 / 6;
float Text_y = upLine_bottom_y;
// 根據Item位置設定時間文字
for (int j = 0; j <timedata.size() ; j++) {
if (index==j){
c.drawText((String)timedata.get(j).get("time"), Text_x, Text_y, mPaint1);
c.drawText((String)timedata.get(j).get("year"), Text_x + 5, Text_y + 20, mPaint2);
}
}
}
}
4,、在Activity中的使用
// times時間軸右邊的時間資料,bitmap是中間的圖片
ry_time.addItemDecoration(new TimezItemdecor(BitmapFactory.decodeResource(getResources(),R.mipmap.earnings),listItem));
5、最終效果: