RecyclerView是安卓開發中經常使用的列表控件,當初google設計它的目的就是用來取代listview和gridview。這篇文章要講的主角是recyclerview的一個附屬品-ItemDecoration。講解的也都是基礎內容,主要有三個部分:java
最終的效果以下(忽略毫無設計的ui):git
github地址:github.com/rangaofei/C…github
ItemDecoration是一個很是簡單的抽象類,它沒有抽象方法,除去廢棄的api,共有三個方法能夠重寫,分別是canvas
//獲取當前view的位置信息
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) //在item背後draw public void onDraw(Canvas c, RecyclerView parent, State state) //在item上邊draw public void onDrawOver(Canvas c, RecyclerView parent, State state) 複製代碼
這三個方法能夠說是三個很是重要的方法,他們之間有着強烈的因果關係。api
首先須要注意的是三個方法的調用順序:ide
理解了以上三個方法,咱們就能夠隨意定製itemdecoration了。ui
這個要引出的知識點是關於getItemOffsets的詳細用法,在這裏會傳過來四個參數(全部的方法中的state暫不討論,它和layoutmanager關係比較密切),主要關注前三個參數:this
上一段簡單的代碼,來實現爲全部的左側添加一個空白google
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
this.layoutOrientation = ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
}
switch (this.layoutOrientation) {
case LinearLayoutManager.VERTICAL:
outRect.set(40, 0, 0, 2);//bottom正常
break;
case LinearLayoutManager.HORIZONTAL://比較懶,沒寫
break;
default:
break;
}
複製代碼
這樣,就在全部的item左側流出來一段空白,接下來就能夠在這段空白上來繪製文字:spa
首先在ondraw方法中分發事件:
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
Log.d("---", "onDraw");
switch (this.layoutOrientation) {
case LinearLayoutManager.VERTICAL:
drawVertical(c, parent);
break;
case LinearLayoutManager.HORIZONTAL:
drawHorizontal(c, parent);
break;
default:
break;
}
}
複製代碼
而後看一下具體的繪製文字流程:
c.save();
final int left;
final int right;
if (parent.getClipToPadding()) {
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
c.clipRect(left, parent.getPaddingTop(), right,
parent.getHeight() - parent.getPaddingBottom());
} else {
left = 0;
right = parent.getWidth();
}
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(view);
String text = String.valueOf(position+1);
float w = textPaint.measureText(text);
c.drawText(text, 20 - w / 2, view.getBottom() - view.getHeight() / 2 + textPaint.getFontMetri().descent, textPaint);
}
c.restore();
複製代碼
這裏要注意兩點,paren.getChildCount是獲取的當前顯示的view的數量,並不會獲取不顯示的view的數量。假如recyclerview裏共有30條數據,而當前屏幕內顯示的只有5條,這paren.getChildCount的值是5,不是30。 int position = parent.getChildAdapterPosition(view)
這段代碼是獲取的當前這個view在30條數據中的位置。
c.drawText(text, 20 - w / 2, view.getBottom() - view.getHeight() / 2 + textPaint.getFontMetri().descent, textPaint);
這段代碼繪製了文字,文字的位置就是20 - w / 2, view.getBottom() - view.getHeight() / 2 + textPaint.getFontMetri().descent
這個座標,假如對繪製文字時座標的獲取不太熟悉的話,須要搜索一下資料。
這個很是簡單,只須要在getitemoffset中判斷便可:
switch (this.layoutOrientation) {
case LinearLayoutManager.VERTICAL:
if (parent.getChildAdapterPosition(view) % 3 == 0) {
outRect.set(40, 0, 0, 100);
} else {
outRect.set(40, 0, 0, 2);
}
break;
case LinearLayoutManager.HORIZONTAL:
break;
default:
break;
}
複製代碼
經過上面代碼,就爲全部的索引能被3整除的位置添加了一個高度爲100的分隔線。看一下效果。
這個方法須要在ondrawover中實現,icon會覆蓋在item上邊,並隨屏幕比例來回移動,廢話很少,直接上代碼:
private void drawOverVertical(Canvas c, RecyclerView parent) {
c.save();
final int left;
final int right;
if (parent.getClipToPadding()) {
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
c.clipRect(left, parent.getPaddingTop(), right,
parent.getHeight() - parent.getPaddingBottom());
} else {
left = 0;
right = parent.getWidth();
}
for (int i = 0; i < parent.getChildCount(); i++) {
View view = parent.getChildAt(i);
int top = view.getTop();
int totalHeight = parent.getHeight() - parent.getPaddingTop() - parent.getPaddingBottom();
float percentT = (float) top / totalHeight;
drawable.setBounds((int) (view.getLeft() + 10 + view.getWidth() * percentT),
view.getTop(),
(int) (view.getLeft() + 58 + view.getWidth() * percentT),
view.getTop() + 48);
drawable.draw(c);
}
}
複製代碼
上面代碼中測量了當前view的top位置相對於recyclerview的高度的比例,在item上實現隨位置滾動而左右滑動的一個icon。
一篇很是簡單的文章,但願能幫助到一些朋友。
另外分享一個本身正在編寫的基於註解的庫: github.com/rangaofei/T…
歡迎提意見