天天看點

【筆記】ItemDecoration——分組布局GroupItemDecoration

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);
        }           

完整代碼