RecyclerView中加載清單需要根據某些約定條件分組很正常,根據字元分組地區,根據月份分組賬單等。如果是在item中控制是否是分組第一個顯示一組的頭部就顯得有點low了。接下來記錄下為分組清單準備的GroupItemDecoration:
GroupBean
ItemDecoration是分割線,添加靈活,為了對應清單中每個item,記錄每個item的身份資訊。一般情況下有以下四個應該是夠了的,如果分組組标題title,組groupId,組内位置index以及每個item上偏移的位置(在getItemOffsets時使用,組内第一個與組内其他成員一般情況下時不一樣的),如果有其他特殊需求也可以自己添加。
/**
* 組标題
*/
private String title;
/**
* 組id
*/
private int groupId;
/**
* 組内位置
*/
private int index;
/**
* 每個item上偏移
*/
private int top;
GroupCallback
組回調,這個接口就是為了友善ItemDecoration擷取每項資訊用的。
public interface GroupCallback {
/**
* 擷取每個item對應的組資訊
*/
GroupBean getGroupBean(int position);
/***
* 擷取每個組員需要的分割View
*/
View getDividerView(int position);
}
GroupItemDecoration
繼承ItemDecoration,實作分割線。重寫getItemOffsets(Rect, View, RecyclerView, State)與onDraw(Canvas, RecyclerView, RecyclerView.State)。
在getItemOffsets方法裡設定每個item的偏移,我們設定了每個item的身份資訊GroupBean,這裡就直接使用getTop()設定上偏移。
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (groupCallback == null) {
return;
}
int position = parent.getChildAdapterPosition(view);
GroupBean groupBean = groupCallback.getGroupBean(position);
if (groupBean != null) {
//設定每個item的上邊距
outRect.top = groupBean.getTop();
}else{
//為null時上邊距為0
outRect.top = 0;
}
}
在onDraw方法中對每個item繪制不同的頭部,擷取每個item身份,并通過getDividerView(int position)擷取每個item對應的分割線View。
for (int i = 0; i < childCount; i++) {
View childView = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(childView);
GroupBean groupBean = groupCallback.getGroupBean(position);
if (groupBean == null) {
continue;
}
View dividerView = groupCallback.getDividerView(position);
if(dividerView==null){
continue;
}
//分割線高度
int dividerHeight = groupBean.getTop();
//分割線上邊沿位置
int top = childView.getTop() + parent.getPaddingTop()-dividerHeight;
//計算設定每個擷取到分割View的寬高
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dividerHeight);
dividerView.setLayoutParams(layoutParams);
dividerView.measure(View.MeasureSpec.makeMeasureSpec(right, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(dividerHeight, View.MeasureSpec.EXACTLY));
//布局大小
dividerView.layout(0, 0, right, dividerHeight);
//必須加,否則可能出現擷取到的bitmap為null
dividerView.setDrawingCacheEnabled(true);
dividerView.buildDrawingCache();
//沒有上面兩句擷取到的就是null
Bitmap bitmap = dividerView.getDrawingCache();
c.drawBitmap(bitmap, left, top, null);
}
完整代碼