RecyclerView 萬能分割線(升級)

效果圖

在這裏插入圖片描述

升級內容

  1. 初始化無需傳入任何參數,一切都是自動獲取
  2. 新增外邊框控制,根據參數設置
  3. 新增帶標題的grid,根據參數設置

具體使用

默認沒有標題,不繪製外邊框

recyclerView.addItemDecoration(new MyDividerItemDecoration().setHasTitle(true).setDrawOuterBorder(true));

全代碼

package cn;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

public class MyDividerItemDecoration extends RecyclerView.ItemDecoration {
    //橫向佈局分割線
    public static final int HORIZONTAL_DIV = RecyclerView.HORIZONTAL;
    //縱向佈局分割線
    public static final int VERTICAL_DIV = RecyclerView.VERTICAL;
    //表格佈局分割線
    public static final int GRID_DIV = 2;
    private int mOrientation;
    private int mDividerWidth = 0;
    private Paint mPaint;

    private boolean isDrawOuterBorder = false;//默認不繪製邊框
    private boolean hasTitle = false;//是否有標題

    /**
     * 默認縱向布分割線
     */
    public MyDividerItemDecoration() {
        this(VERTICAL_DIV);
    }

    /**
     * @param orientation 方向類型
     */
    public MyDividerItemDecoration(int orientation) {
        this(orientation, Color.parseColor("#EEEEEE"), 2);
    }

    /**
     * @param orientation 方向類型
     * @param color       分割線顏色
     * @param divWidth    分割線寬度
     */
    public MyDividerItemDecoration(int orientation, int color, int divWidth) {
        this.setOrientation(orientation);
        mDividerWidth = divWidth;
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(color);
        mPaint.setStyle(Paint.Style.FILL);
    }

    private int getRealOrientation(RecyclerView parent) {
        RecyclerView.LayoutManager manager = parent.getLayoutManager();
        if (manager instanceof GridLayoutManager) {
            return GRID_DIV;
        } else if (manager instanceof LinearLayoutManager) {
            int o = ((LinearLayoutManager) manager).getOrientation();
            if (o == RecyclerView.HORIZONTAL) {
                return HORIZONTAL_DIV;
            } else {
                return VERTICAL_DIV;
            }
        }
        return VERTICAL_DIV;
    }

    @Override
    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        mOrientation = getRealOrientation(parent);
        switch (mOrientation) {
            case HORIZONTAL_DIV:
                //橫向佈局分割線
                drawHorizontal(c, parent);
                break;
            case VERTICAL_DIV:
                //縱向佈局分割線
                drawVertical(c, parent);
                break;
            case GRID_DIV:
                //表格格局分割線
                drawGrid(c, parent);
                break;
            default:
                //縱向佈局分割線
                drawVertical(c, parent);
                break;
        }
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        int itemPosition = parent.getChildAdapterPosition(view);
        RecyclerView.Adapter mAdapter = parent.getAdapter();
        if (mAdapter != null) {
            int mChildCount = mAdapter.getItemCount();
            mOrientation = getRealOrientation(parent);
            switch (mOrientation) {
                case HORIZONTAL_DIV:
                    /**
                     * 橫向佈局分割線
                     * <p>
                     *     如果是第一個Item,則不需要分割線
                     * </p>
                     */
                    if (itemPosition != 0) {
                        outRect.set(mDividerWidth, 0, 0, 0);
                    }
                    break;
                case VERTICAL_DIV:
                    /**
                     * 縱向佈局分割線
                     * <p>
                     *     如果是第一個Item,則不需要分割線
                     * </p>
                     */
                    if (itemPosition != 0) {
                        outRect.set(0, mDividerWidth, 0, 0);
                    }
                    break;
                case GRID_DIV:
                    /**
                     * 表格格局分割線
                     * <p>
                     *      1:當是第一個Item的時候,四周全部需要分割線
                     *      2:當是第一行Item的時候,需要額外添加頂部的分割線
                     *      3:當是第一列Item的時候,需要額外添加左側的分割線
                     *      4:默認情況全部添加底部和右側的分割線
                     * </p>
                     */
                    RecyclerView.LayoutManager mLayoutManager = parent.getLayoutManager();
                    if (mLayoutManager instanceof GridLayoutManager) {
                        GridLayoutManager mGridLayoutManager = (GridLayoutManager) mLayoutManager;
                        int mSpanCount = mGridLayoutManager.getSpanCount();
                        int top = 0, left = 0, right = 0, bottom = 0;
                        int realIndex = 0;
                        if (hasTitle) {
                            realIndex = itemPosition - 1;
                        }
                        int maxRow = mChildCount / mSpanCount + (mChildCount % mSpanCount == 0 ? 0 : 1);
                        int indexRow = (realIndex + 1) / mSpanCount + ((realIndex + 1) % mSpanCount == 0 ? 0 : 1);
                        if ((realIndex + 1) <= mSpanCount && isDrawOuterBorder) {
                            top = mDividerWidth;
                        }
                        if (((realIndex + mSpanCount) % mSpanCount) == 0 && isDrawOuterBorder) {
                            left = mDividerWidth;
                        }
                        if ((realIndex + 1) % mSpanCount != 0 || isDrawOuterBorder) {
                            right = mDividerWidth;
                        }
                        if (indexRow != maxRow || isDrawOuterBorder) {
                            bottom = mDividerWidth;
                        }
                        outRect.set(left, top, right, bottom);
                    }
                    break;
                default:
                    //縱向佈局分割線
                    if (itemPosition != (mChildCount - 1)) {
                        outRect.set(0, 0, 0, mDividerWidth);
                    }
                    break;
            }
        }
    }

    /**
     * 繪製橫向列表分割線
     *
     * @param c      繪製容器
     * @param parent RecyclerView
     */
    private void drawHorizontal(Canvas c, RecyclerView parent) {
        int mChildCount = parent.getChildCount();
        for (int i = 0; i < mChildCount; i++) {
            if (i == 0 && !isDrawOuterBorder) continue;
            View mChild = parent.getChildAt(i);
            drawLeft(c, mChild, parent);
        }
    }

    /**
     * 繪製縱向列表分割線
     *
     * @param c      繪製容器
     * @param parent RecyclerView
     */
    private void drawVertical(Canvas c, RecyclerView parent) {
        int mChildCount = parent.getChildCount();
        for (int i = 0; i < mChildCount; i++) {
            if (i == 0 && !isDrawOuterBorder) continue;
            View mChild = parent.getChildAt(i);
            drawTop(c, mChild, parent);
        }
    }

    /**
     * 繪製表格類型分割線
     *
     * @param c      繪製容器
     * @param parent RecyclerView
     */
    private void drawGrid(Canvas c, RecyclerView parent) {
        int mChildCount = parent.getChildCount();
        for (int i = 0; i < mChildCount; i++) {
            View mChild = parent.getChildAt(i);
            RecyclerView.LayoutManager mLayoutManager = parent.getLayoutManager();
            if (mLayoutManager instanceof GridLayoutManager) {
                GridLayoutManager mGridLayoutManager = (GridLayoutManager) mLayoutManager;
                int mSpanCount = mGridLayoutManager.getSpanCount();
                int realIndex = 0;
                if (hasTitle) {
                    if (i == 0) {
                        drawBottom(c, mChild, parent);
                        continue;
                    }
                    realIndex = i - 1;
                }
                if ((realIndex + 1) <= mSpanCount && isDrawOuterBorder) {
                    drawTop(c, mChild, parent);
                }
                if (((realIndex + mSpanCount) % mSpanCount) == 0 && isDrawOuterBorder) {
                    drawLeft(c, mChild, parent);
                }
                if ((realIndex + 1) % mSpanCount != 0 || isDrawOuterBorder) {
                    drawRight(c, mChild, parent);
                }
                int maxRow = mChildCount / mSpanCount + (mChildCount % mSpanCount == 0 ? 0 : 1);
                int indexRow = (realIndex + 1) / mSpanCount + ((realIndex + 1) % mSpanCount == 0 ? 0 : 1);
                if (indexRow != maxRow || isDrawOuterBorder) {
                    drawBottom(c, mChild, parent);
                }
            }
        }
    }

    /**
     * 繪製右邊分割線
     *
     * @param c            繪製容器
     * @param mChild       對應ItemView
     * @param recyclerView RecyclerView
     */
    private void drawLeft(Canvas c, View mChild, RecyclerView recyclerView) {
        RecyclerView.LayoutParams mChildLayoutParams = (RecyclerView.LayoutParams) mChild.getLayoutParams();
        int left = mChild.getLeft() - mDividerWidth - mChildLayoutParams.leftMargin;
        int top = mChild.getTop() - mChildLayoutParams.topMargin;
        int right = mChild.getLeft() - mChildLayoutParams.leftMargin;
        int bottom;
        if (isGridLayoutManager(recyclerView)) {
            bottom = mChild.getBottom() + mChildLayoutParams.bottomMargin + mDividerWidth;
        } else {
            bottom = mChild.getBottom() + mChildLayoutParams.bottomMargin;
        }
        c.drawRect(left, top, right, bottom, mPaint);
    }

    /**
     * 繪製頂部分割線
     *
     * @param c            繪製容器
     * @param mChild       對應ItemView
     * @param recyclerView RecyclerView
     */
    private void drawTop(Canvas c, View mChild, RecyclerView recyclerView) {
        RecyclerView.LayoutParams mChildLayoutParams = (RecyclerView.LayoutParams) mChild.getLayoutParams();
        int left;
        int top = mChild.getTop() - mChildLayoutParams.topMargin - mDividerWidth;
        int right = mChild.getRight() + mChildLayoutParams.rightMargin;
        int bottom = mChild.getTop() - mChildLayoutParams.topMargin;
        if (isGridLayoutManager(recyclerView)) {
            left = mChild.getLeft() - mChildLayoutParams.leftMargin - mDividerWidth;
        } else {
            left = mChild.getLeft() - mChildLayoutParams.leftMargin;
        }
        c.drawRect(left, top, right, bottom, mPaint);
    }

    /**
     * 繪製右邊分割線
     *
     * @param c            繪製容器
     * @param mChild       對應ItemView
     * @param recyclerView RecyclerView
     */
    private void drawRight(Canvas c, View mChild, RecyclerView recyclerView) {
        RecyclerView.LayoutParams mChildLayoutParams = (RecyclerView.LayoutParams) mChild.getLayoutParams();
        int left = mChild.getRight() + mChildLayoutParams.rightMargin;
        int top;
        int right = left + mDividerWidth;
        int bottom = mChild.getBottom() + mChildLayoutParams.bottomMargin;
        if (isGridLayoutManager(recyclerView)) {
            top = mChild.getTop() - mChildLayoutParams.topMargin - mDividerWidth;
        } else {
            top = mChild.getTop() - mChildLayoutParams.topMargin;
        }
        c.drawRect(left, top, right, bottom, mPaint);
    }

    /**
     * 繪製底部分割線
     *
     * @param c            繪製容器
     * @param mChild       對應ItemView
     * @param recyclerView RecyclerView
     */
    private void drawBottom(Canvas c, View mChild, RecyclerView recyclerView) {
        RecyclerView.LayoutParams mChildLayoutParams = (RecyclerView.LayoutParams) mChild.getLayoutParams();
        int left = mChild.getLeft() - mChildLayoutParams.leftMargin;
        int top = mChild.getBottom() + mChildLayoutParams.bottomMargin;
        int bottom = top + mDividerWidth;
        int right;
        if (isGridLayoutManager(recyclerView)) {
            right = mChild.getRight() + mChildLayoutParams.rightMargin + mDividerWidth;
        } else {
            right = mChild.getRight() + mChildLayoutParams.rightMargin;
        }
        c.drawRect(left, top, right, bottom, mPaint);
    }

    /**
     * 判斷RecyclerView所加載LayoutManager是否爲GridLayoutManager
     *
     * @param recyclerView RecyclerView
     * @return 是GridLayoutManager返回true,否則返回false
     */
    private boolean isGridLayoutManager(RecyclerView recyclerView) {
        RecyclerView.LayoutManager mLayoutManager = recyclerView.getLayoutManager();
        return (mLayoutManager instanceof GridLayoutManager);
    }

    /**
     * 初始化分割線類型
     *
     * @param orientation 分割線類型
     */
    public void setOrientation(int orientation) {
        if (mOrientation != HORIZONTAL_DIV && mOrientation != VERTICAL_DIV && mOrientation != GRID_DIV) {
            throw new IllegalArgumentException("MyDividerItemDecoration:分割線類型設置異常");
        } else {
            this.mOrientation = orientation;
        }
    }

    /**
     * 是否繪製外邊框
     *
     * @param isDrawOuterBorder
     * @return
     */
    public MyDividerItemDecoration setDrawOuterBorder(boolean isDrawOuterBorder) {
        this.isDrawOuterBorder = isDrawOuterBorder;
        return this;
    }

    public MyDividerItemDecoration setHasTitle(boolean hasTitle) {
        this.hasTitle = hasTitle;
        return this;
    }
}

知識點

帶標題的RecyclerView,自行百度。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章