我們都知道,使用 RecyclerView 時(shí) ,我們不能像 ListView 那樣通過 setDivider() 的方式來設(shè)置分割線,好在 Android 為我們提供了定制性更強(qiáng)的 ItemDecoration 來為 RecyclerView 設(shè)置分割線。
什么是 ItemDecoration ?
顧名思義 ItemDecoration 就是 Item 的裝飾,我們可以在 Item 的上下左右添加自定義的裝飾,比如 橫線,圖案。同時(shí)系統(tǒng)已經(jīng)為我們提供了一個(gè) DividerItemDecoration, 如果這個(gè) DividerItemDecoration 不滿足我們的需求,我們就可以通過自定義 ItemDecoration 來實(shí)現(xiàn)了。
下面我們看下系統(tǒng)的 DividerItemDecoration :
引入 DividerItemDecoration(系統(tǒng)提供)
DividerItemDecoration 的使用非常簡單,只需添加下面代碼即可:
DividerItemDecoration decoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
recyclerView.addItemDecoration(decoration);
效果:

如果想要修改 DividerItemDecoration 的顏色和高度,可以調(diào)用它的 setDrawable(drawable) 設(shè)置一個(gè) Drawable 對象
// MainActivity.java
DividerItemDecoration decoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
Drawable dividerDrawable = getResources().getDrawable(R.drawable.drawable_divider);
decoration.setDrawable(dividerDrawable);
recyclerView.addItemDecoration(decoration);
// res/drawable/drawable_divider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
android:shape="rectangle">
<!-- 漸變色 -->
<gradient
android:angle="135"
android:centerColor="#4CAF50"
android:endColor="#2E7D32"
android:startColor="#81C784"
android:type="linear" />
<size android:height="1dp" />
</shape>
效果:

自定義 ItemDecoration
自定義 ItemDecoration ,主要需要重寫以下三個(gè)方法:
/**
* 自定義 ItemDecoration
*/
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
}
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
}
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDrawOver(c, parent, state);
}
1. getItemOffsets()
getItemOffsets() 主要作用是在 item 的四周留下邊距,效果和 margin 類似,item 的四周留下邊距后,我們就可以通過 onDraw() 在這個(gè)邊距上繪制了。
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)
(1) 參數(shù) Rect outRect : 表示 item 的上下左右所留下的邊距。其中 outRect 的 left, top,right,bottom 即為 item 四周留下的邊距的距離,默認(rèn)都為 0 ;示意圖如下:
(2) 參數(shù) View view : 指當(dāng)前 item 的 View 對象;
(3) 參數(shù) RecyclerView parent : 指 RecyclerView 本身;
(4) RecyclerView.State state : 指 RecyclerView 當(dāng)前的狀態(tài);
1.1 getItemOffsets() 應(yīng)用例子:
既然 getItemOffsets(Rect outRect) 方法可以設(shè)置 item 四周的邊距大小,那就可以設(shè)置 recyclerview 背景色和 item 四周的邊距,使得 item 四周的邊距透出 recyclerview 背景色來達(dá)到分割線的目的。
當(dāng)然 item 的背景色需要和 recyclerview 的背景色不一致才有效果;
首先將 recyclerview 的背景色設(shè)置為 colorAccent 紅色, 將 item 的背景色設(shè)置為 白色:
<!--- activity_main.xml ----->
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent" />
</android.support.constraint.ConstraintLayout>
<!--- item_recycler.xml ----->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#fff"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="40dp"
android:gravity="center_vertical" />
</LinearLayout>
然后繼承 ItemDecoration 類,重寫 getOffsets() 方法,將 outRect 的上邊距 top 設(shè)置為 10px;
/**
* 自定義 ItemDecoration
*/
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.top = 10; // 10px
}
}
最后將這個(gè) LinearItemDecoration 添加到 RecyclerView 中:
LinearItemDecoration decoration = new LinearItemDecoration();
recyclerView.addItemDecoration(decoration);
效果如下(下方的紅色是 因?yàn)镽ecyclerView 高度為 match_parent ,但 item 數(shù)據(jù)只有 5 條):

從效果圖可以看出:每一個(gè) item 的 頂部都有一個(gè)紅色的背景線,包括第一個(gè) item 頂部也有(怎么解決呢?見 2.1 節(jié)詳解),
同理,我們可以設(shè)置為 底部 10px,左側(cè) 20px ,右側(cè) 40px;
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.bottom = 10;
outRect.left = 20;
outRect.right = 40;
}
}
效果:

可以看到:每個(gè) item 的左測,底部,右側(cè)都有了間距,露出了 RecyclerView 的背景色了。
2. onDraw()
@Override
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(canvas, parent, state);
}
onDraw() 函數(shù)中的 parent , state 參數(shù)和 getItemOffsets() 方法中的參數(shù)含義是一樣的,canvas 參數(shù)是 getItemOffsets() 函數(shù)所留下的左右上下的空白區(qū)域?qū)?yīng)的 Canvas 畫布對象。我們可以在這個(gè)區(qū)域中利用 Paint 畫筆繪制任何圖形。
比如在 item 左側(cè)繪制一個(gè) 空心圓。
/**
* 自定義 ItemDecoration
*/
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
private static final String TAG = "LinearItemDecoration";
private Paint paint;
public LinearItemDecoration() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
Log.e(TAG, "getItemOffsets: " );
outRect.bottom = 10;
outRect.left = 100;
outRect.right = 40;
}
@Override
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(canvas, parent, state);
Log.e(TAG, "onDraw: ");
for (int i = 0; i < parent.getChildCount(); i++) {
View childView = parent.getChildAt(i);
canvas.drawCircle(50, childView.getTop() + childView.getHeight() / 2, 20, paint);
}
}
}
效果:

我們在 getItemOffsets() 和 onDraw() 方法中都添加了日志,日志打印如下:

從日志中可以看出: getItemOffsets() 方法執(zhí)行了 5 遍,和 數(shù)據(jù)源個(gè)數(shù)是一樣的,但 onDraw() 方法只執(zhí)行了一遍,由此我們知道, getItemOffsets() 是針對每個(gè) item 都會執(zhí)行一次,也就是說 每個(gè) item 的 outRect 可以設(shè)置為不同值,但是 onDraw(),onDrawOver() 是針對 ItemDecoration 的,不是針對 item 的,只執(zhí)行一次。所以我們在 onDraw() ,onDrawOver() 中繪制的時(shí)候,需要遍歷每個(gè) item 進(jìn)行繪制。
優(yōu)雅獲取 outRect 中的值
在上面例子中,我們在 onDraw 中獲取 outRect 中的值都是寫成計(jì)算好的固定值,顯然這種硬編碼的方式不利于擴(kuò)展,其實(shí),我們可以通過 LayoutManager 來獲取 getItemOffsets() 中設(shè)置的 outRect 的值。
@Override
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(canvas, parent, state);
Log.e(TAG, "onDraw: ");
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
for (int i = 0; i < parent.getChildCount(); i++) {
View childView = parent.getChildAt(i);
int leftDecorationWidth = layoutManager.getLeftDecorationWidth(childView);
int topDecorationHeight = layoutManager.getTopDecorationHeight(childView);
int rightDecorationWidth = layoutManager.getRightDecorationWidth(childView);
int bottomDecorationHeight = layoutManager.getBottomDecorationHeight(childView);
}
}
上面硬編碼可以改成:
@Override
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(canvas, parent, state);
Log.e(TAG, "onDraw: ");
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
for (int i = 0; i < parent.getChildCount(); i++) {
View childView = parent.getChildAt(i);
int leftDecorationWidth = layoutManager.getLeftDecorationWidth(childView);
int left = leftDecorationWidth / 2;
canvas.drawCircle(left, childView.getTop() + childView.getHeight() / 2, 20, paint);
}
}
2.1 擴(kuò)展1 -- 減少背景設(shè)置,避免過度繪制
為了減少過度繪制,我們將 activity_main 中 RecyclerView , item_recycler 中的背景全部去掉,不設(shè)置任何背景,然后在 LinearItemDecoration 中進(jìn)行純繪制分割線,代碼如下:
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
private static final String TAG = "LinearItemDecoration";
private Paint paint;
private Paint dividerPaint;
public LinearItemDecoration() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dividerPaint.setColor(Color.parseColor("#e6e6e6"));
dividerPaint.setStyle(Paint.Style.FILL);
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
Log.e("ItemOffsets", "getItemOffsets: ");
outRect.bottom = 5;
outRect.left = 100;
}
@Override
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(canvas, parent, state);
Log.e(TAG, "onDraw: ");
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
for (int i = 0; i < parent.getChildCount(); i++) {
View childView = parent.getChildAt(i);
int leftDecorationWidth = layoutManager.getLeftDecorationWidth(childView);
int topDecorationHeight = layoutManager.getTopDecorationHeight(childView);
int rightDecorationWidth = layoutManager.getRightDecorationWidth(childView);
int bottomDecorationHeight = layoutManager.getBottomDecorationHeight(childView);
int left = leftDecorationWidth / 2;
canvas.drawCircle(left, childView.getTop() + childView.getHeight() / 2, 20, paint);
// getItemOffsets()中的設(shè)置的是 bottom = 5px;所以在 drawRect 時(shí),top 為 childView.getBottom,bottom為top+bottomDecorationHeight
canvas.drawRect(new Rect(
leftDecorationWidth,
childView.getBottom(),
childView.getWidth() + leftDecorationWidth,
childView.getBottom() + bottomDecorationHeight
), dividerPaint);
}
}
@Override
public void onDrawOver(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDrawOver(canvas, parent, state);
}
}
效果:

注意: 上面 getItemOffsets() 中設(shè)置的是 bottom = 5px; 所以在 onDraw() 方法的 drawRect 時(shí),top值為 childView.getBottom, bottom值為 top+bottomDecorationHeight。

同理:getItemOffsets() 中設(shè)置是 top = 5px, 那么在 onDraw() 方法 drawRect 時(shí),bottom 值為 childView.getTop() , top 值為 bottom - topDecorationHeight
2.2 擴(kuò)展2 -- 實(shí)現(xiàn)豎直進(jìn)度分割線
在 getItemOffsets() 方法中左側(cè)留下空白區(qū)域,然后在 onDraw() 方法中繪制 圓和 豎線。代碼如下:
<!--- item_recycler.xml ---->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:gravity="center_vertical"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#332"
android:textSize="16sp"
tools:text="我是 title" />
<TextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center_vertical"
android:textColor="#666"
android:textSize="14sp"
tools:text="woshi" />
</LinearLayout>
<!--- activity_main.xml --->
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#dfdfdf" />
</android.support.constraint.ConstraintLayout>
// ProgressItemDecoration.java
public class ProgressItemDecoration extends RecyclerView.ItemDecoration {
private Context context;
private Paint circlePaint;
private Paint linePaint;
private int radius;
private int curPosition = 0; // 當(dāng)前進(jìn)行中的位置
public ProgressItemDecoration(Context context) {
this.context = context;
circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
circlePaint.setColor(context.getResources().getColor(R.color.colorPrimary));
circlePaint.setStyle(Paint.Style.FILL);
radius = dp2Px(8);
circlePaint.setStrokeWidth(dp2Px(2));
linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
linePaint.setColor(context.getResources().getColor(R.color.colorPrimary));
linePaint.setStrokeWidth(dp2Px(2));
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.top = dp2Px(20);
outRect.left = dp2Px(50);
outRect.right = dp2Px(20);
}
@Override
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(canvas, parent, state);
int childCount = parent.getChildCount();
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
for (int i = 0; i < childCount; i++) {
View childView = parent.getChildAt(i);
int leftDecorationWidth = layoutManager.getLeftDecorationWidth(childView);
int topDecorationHeight = layoutManager.getTopDecorationHeight(childView);
// 獲取當(dāng)前 item 是 recyclerview 的第幾個(gè) childview
int childLayoutPosition = parent.getChildLayoutPosition(childView);
float startX = leftDecorationWidth / 2;
float stopX = startX;
// 圓頂部部分豎線,起點(diǎn) Y
float topStartY = childView.getTop() - topDecorationHeight;
// 圓頂部部分豎線,終點(diǎn) Y
float topStopY = childView.getTop() + childView.getHeight() / 2 - radius;
// 圓底部部分豎線,起點(diǎn) Y
float bottomStartY = childView.getTop() + childView.getHeight() / 2 + radius;
// 圓底部部分豎線,終點(diǎn) Y
float bottomStopY = childView.getBottom();
// 位置超過 curPosition 時(shí),豎線顏色設(shè)置為淺色
if (childLayoutPosition > curPosition) {
linePaint.setColor(context.getResources().getColor(R.color.colorPrimaryTint));
circlePaint.setColor(context.getResources().getColor(R.color.colorPrimaryTint));
circlePaint.setStyle(Paint.Style.STROKE);
} else {
linePaint.setColor(context.getResources().getColor(R.color.colorPrimary));
circlePaint.setColor(context.getResources().getColor(R.color.colorPrimary));
circlePaint.setStyle(Paint.Style.FILL);
}
// 繪制圓
if (childLayoutPosition == curPosition) {
circlePaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(leftDecorationWidth / 2, childView.getTop() + childView.getHeight() / 2, dp2Px(2), circlePaint);
}
canvas.drawCircle(leftDecorationWidth / 2, childView.getTop() + childView.getHeight() / 2, radius, circlePaint);
// 繪制豎線 , 第 0 位置上只需繪制 下半部分
if (childLayoutPosition == 0) {
// 當(dāng)前 item position = curPosition 時(shí),繪制下半部分豎線時(shí),顏色設(shè)置為淺色
if (childLayoutPosition == curPosition) {
linePaint.setColor(context.getResources().getColor(R.color.colorPrimaryTint));
}
canvas.drawLine(startX, bottomStartY, startX, bottomStopY, linePaint);
// 最后位置上,只需繪制上半部分
} else if (childLayoutPosition == parent.getAdapter().getItemCount() - 1) {
canvas.drawLine(startX, topStartY, startX, topStopY, linePaint);
} else {
// 都要繪制
canvas.drawLine(startX, topStartY, startX, topStopY, linePaint);
// 當(dāng)前 item position = curPosition 時(shí),繪制下半部分豎線時(shí),顏色設(shè)置為淺色
if (childLayoutPosition == curPosition) {
linePaint.setColor(context.getResources().getColor(R.color.colorPrimaryTint));
}
canvas.drawLine(startX, bottomStartY, startX, bottomStopY, linePaint);
}
}
}
/**
* 設(shè)置進(jìn)行中的位置
*
* @param recyclerView
* @param position
*/
public void setDoingPosition(RecyclerView recyclerView, int position) {
if (recyclerView == null) {
throw new IllegalArgumentException("RecyclerView can't be null");
}
if (recyclerView.getAdapter() == null) {
throw new IllegalArgumentException("RecyclerView Adapter can't be null");
}
if (position < 0) {
throw new IllegalArgumentException("position can't be less than 0");
}
recyclerView.getLayoutManager().getItemCount();
if (position > recyclerView.getAdapter().getItemCount() - 1) {
throw new IllegalArgumentException("position can't be greater than item count");
}
this.curPosition = position;
}
private int dp2Px(int value) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, context.getResources().getDisplayMetrics());
}
}
// MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.rv_recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
List<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
String data = "test data - " + i;
if (i % 2 == 0) {
data = data + "\n" + "這是測試數(shù)據(jù) " + i;
}
list.add(data);
}
BaseRecyclerAdapter adapter = new BaseRecyclerAdapter<String>(list, R.layout.item_recycler) {
@Override
protected void bind(BaseRecyclerAdapter<String> adapter, BaseViewHolder holder, String data, int position) {
holder.setText(R.id.tv_title, data);
holder.setText(R.id.tv_time, new Date().toString());
}
};
recyclerView.setAdapter(adapter);
ProgressItemDecoration decoration = new ProgressItemDecoration(this);
decoration.setDoingPosition(recyclerView, 0);
recyclerView.addItemDecoration(decoration);
}
}
效果:

3. onDrawOver()
當(dāng)我們將上面例子中繪制左側(cè)的空心圓的位置改為: 圓心 x 坐標(biāo)為 leftDecorationWidth,同時(shí)將 item 背景色設(shè)置為 白色:
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
Log.e("ItemOffsets", "getItemOffsets: ");
outRect.bottom = 5;
outRect.left = 100;
}
@Override
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(canvas, parent, state);
Log.e(TAG, "onDraw: ");
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
for (int i = 0; i < parent.getChildCount(); i++) {
View childView = parent.getChildAt(i);
int leftDecorationWidth = layoutManager.getLeftDecorationWidth(childView);
int bottomDecorationHeight = layoutManager.getBottomDecorationHeight(childView);
int left = leftDecorationWidth / 2;
// canvas.drawCircle(left, childView.getTop() + childView.getHeight() / 2, 20, paint);
canvas.drawCircle(leftDecorationWidth, childView.getTop() + childView.getHeight() / 2, 20, paint);
// getItemOffsets()中的設(shè)置的是 bottom = 5px;所以在 drawRect 時(shí),top 為 childView.getBottom,bottom為top+bottomDecorationHeight
canvas.drawRect(new Rect(
leftDecorationWidth,
childView.getBottom(),
childView.getWidth() + leftDecorationWidth,
childView.getBottom() + bottomDecorationHeight
), dividerPaint);
}
}
效果:

我們發(fā)現(xiàn):繪制的空心圓被 item 遮擋了右邊部分,變?yōu)椴豢梢娏?,這是因?yàn)樵谶@個(gè)繪制的流程中,先調(diào)用 ItemDecoration 的 onDraw() 方法,然后再調(diào)用 item 的 onDraw() 方法,最后再調(diào)用 ItemDecoration 的 onDrawOver() 方法。
因此,當(dāng)我們想要在 item 的繪制顯示一些內(nèi)容時(shí),將繪制的邏輯寫在 onDrawOver() 方法即可。
下面我們實(shí)現(xiàn)在 item 與 左側(cè) decoration 交匯處繪制一個(gè) apple icon ,并將 item 中的內(nèi)容文本設(shè)置為居中顯示,代碼如下:
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
private static final String TAG = "LinearItemDecoration";
private Paint paint;
private Paint dividerPaint;
private Bitmap iconBitmap;
public LinearItemDecoration(Context context) {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
dividerPaint.setColor(Color.parseColor("#e6e6e6"));
dividerPaint.setStyle(Paint.Style.FILL);
iconBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.ios);
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
Log.e("ItemOffsets", "getItemOffsets: ");
outRect.bottom = 5;
outRect.left = 100;
}
@Override
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(canvas, parent, state);
Log.e(TAG, "onDraw: ");
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
for (int i = 0; i < parent.getChildCount(); i++) {
View childView = parent.getChildAt(i);
int leftDecorationWidth = layoutManager.getLeftDecorationWidth(childView);
int bottomDecorationHeight = layoutManager.getBottomDecorationHeight(childView);
int left = leftDecorationWidth / 2;
// canvas.drawCircle(left, childView.getTop() + childView.getHeight() / 2, 20, paint);
// canvas.drawCircle(leftDecorationWidth, childView.getTop() + childView.getHeight() / 2, 20, paint);
// getItemOffsets()中的設(shè)置的是 bottom = 5px;所以在 drawRect 時(shí),top 為 childView.getBottom,bottom為top+bottomDecorationHeight
canvas.drawRect(new Rect(
leftDecorationWidth,
childView.getBottom(),
childView.getWidth() + leftDecorationWidth,
childView.getBottom() + bottomDecorationHeight
), dividerPaint);
}
}
@Override
public void onDrawOver(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDrawOver(canvas, parent, state);
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
for (int i = 0; i < parent.getChildCount(); i++) {
View childView = parent.getChildAt(i);
int leftDecorationWidth = layoutManager.getLeftDecorationWidth(childView);
canvas.drawBitmap(iconBitmap, leftDecorationWidth - iconBitmap.getWidth() / 2,
childView.getTop() + childView.getHeight() / 2 - iconBitmap.getHeight() / 2, paint);
}
}
}
效果:
