Recyclerview ItemDecoration 通用分割线

2022-07-30,,,

目前还没有试验瀑布流 只写了list 和 grid 待完善

public class CommonDividerItemDecoration extends RecyclerView.ItemDecoration {


    public final static int HORIZONTAL = LinearLayoutManager.HORIZONTAL;

    public final static int VERTICAL = LinearLayoutManager.VERTICAL;

    public final static float DEFAULT_SPACE = 0.5f;

    private Context mContext;
    private int mOrientation;
    private int mRectSpace;
    private int mLeftEdgeSpace;
    private int mTopEdgeSpace;
    private int mRightEdgeSpace;
    private int mBottomEdgeSpace;
    private boolean isIncludeLeft;
    private boolean isIncludeTop;
    private boolean isIncludeRight;
    private boolean isIncludeBottom;
    private Paint mPaint;
    private int mPaintColor;
    private int mMaxSpanGroupIndex;

    private CommonDividerItemDecoration(Builder builder) {
        this.mContext = builder.context;
        this.mOrientation = builder.orientation;
        this.mRectSpace = builder.rectSpace;
        this.mLeftEdgeSpace = builder.leftEdgeSpace;
        this.mTopEdgeSpace = builder.topEdgeSpace;
        this.mRightEdgeSpace = builder.rightEdgeSpace;
        this.mBottomEdgeSpace = builder.bottomEdgeSpace;
        this.isIncludeLeft = builder.isIncludeLeft;
        this.isIncludeTop = builder.isIncludeTop;
        this.isIncludeRight = builder.isIncludeRight;
        this.isIncludeBottom = builder.isIncludeBottom;
        this.mPaintColor = builder.paintColor;
        init();
    }

    private void init() {
        this.mPaint = new Paint();
        this.mPaint.setAntiAlias(true);
        this.mPaint.setStyle(Paint.Style.FILL);
        this.mPaint.setColor(this.mPaintColor);
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int childCount = Objects.requireNonNull(parent.getAdapter()).getItemCount();
        if (childCount == 0) return;
        int position = parent.getChildAdapterPosition(view);
        view.setTag(position);
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
            GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup();
            int spanCount = gridLayoutManager.getSpanCount();
            mMaxSpanGroupIndex = spanSizeLookup.getSpanGroupIndex(parent.getAdapter().getItemCount() - 1, spanCount);
            if (isFirsColumn(position, spanCount)) {
                if (isFirstRow(position, spanCount)) {
                    outRect.set(isIncludeLeft ? mLeftEdgeSpace : 0, isIncludeTop ? mTopEdgeSpace : 0, mRectSpace, mRectSpace);
                } else if (isLastRow(position, spanCount, childCount)) {
                    outRect.set(isIncludeLeft ? mLeftEdgeSpace : 0, 0, mRectSpace, isIncludeBottom ? mBottomEdgeSpace : 0);
                } else {
                    outRect.set(isIncludeLeft ? mLeftEdgeSpace : 0, 0, mRectSpace, mRectSpace);
                }
            } else if (isFirstRow(position, spanCount)) {
                if (isLastColumn(position, spanCount)) {
                    outRect.set(0, isIncludeTop ? mTopEdgeSpace : 0, isIncludeRight ? mRightEdgeSpace : 0, mRectSpace);
                } else {
                    outRect.set(0, isIncludeTop ? mTopEdgeSpace : 0, mRectSpace, mRectSpace);
                }
            } else if (isLastColumn(position, spanCount)) {
                if (isLastRow(position, spanCount, childCount)) {
                    outRect.set(0, 0, isIncludeRight ? mRightEdgeSpace : 0, isIncludeBottom ? mBottomEdgeSpace : 0);
                } else {
                    outRect.set(0, 0, isIncludeRight ? mRightEdgeSpace : 0, mRectSpace);
                }
            } else if (isLastRow(position, spanCount, childCount)) {
                outRect.set(0, 0, mRectSpace, isIncludeBottom ? mBottomEdgeSpace : 0);
            } else {
                outRect.set(0, 0, mRectSpace, mRectSpace);
            }
        } else if (layoutManager instanceof LinearLayoutManager) {
            if (mOrientation == VERTICAL) {
                if (position == 0) {//默认的只有一条数据的话 底部分割线保留 如果需要特殊处理再说
                    outRect.set(isIncludeLeft ? mLeftEdgeSpace : 0, isIncludeTop ? mTopEdgeSpace : 0
                            , isIncludeRight ? mRightEdgeSpace : 0, mRectSpace);
                } else if (position == childCount - 1) {
                    outRect.set(isIncludeLeft ? mLeftEdgeSpace : 0, 0
                            , isIncludeRight ? mRightEdgeSpace : 0, isIncludeBottom ? mBottomEdgeSpace : 0);
                } else {
                    outRect.set(isIncludeLeft ? mLeftEdgeSpace : 0, 0
                            , isIncludeRight ? mRightEdgeSpace : 0, mRectSpace);
                }
            } else {
                if (position == 0) {
                    outRect.set(isIncludeLeft ? mLeftEdgeSpace : 0, isIncludeTop ? mTopEdgeSpace : 0
                            , mRectSpace, isIncludeBottom ? mBottomEdgeSpace : 0);
                } else if (position == childCount - 1) {
                    outRect.set(0, isIncludeTop ? mTopEdgeSpace : 0
                            , isIncludeRight ? mRightEdgeSpace : 0, isIncludeBottom ? mBottomEdgeSpace : 0);
                } else {
                    outRect.set(0, isIncludeTop ? mTopEdgeSpace : 0
                            , mRectSpace, isIncludeBottom ? mBottomEdgeSpace : 0);
                }
            }
        } else {
            if (mOrientation == VERTICAL) {

            } else {

            }
        }
    }

    @Override
    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.onDraw(c, parent, state);
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            drawGridSpace(c, parent);
        } else if (layoutManager instanceof LinearLayoutManager) {
            if (mOrientation == VERTICAL) {
                drawListVertical(c, parent);
            } else {
                drawListHorizontal(c, parent);
            }
        } else {
            //TODO
        }
    }

    private void drawListVertical(Canvas c, RecyclerView parent) {
        final int childCount = parent.getChildCount();
        final int itemCount = Objects.requireNonNull(parent.getAdapter()).getItemCount();
        if (childCount == 0) return;

        final int left = isIncludeLeft ? parent.getPaddingLeft() + mLeftEdgeSpace : parent.getPaddingLeft();
        final int right = isIncludeRight ? parent.getWidth() - parent.getPaddingRight() - mRightEdgeSpace : parent.getWidth() - parent.getPaddingRight();

        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            int position = parent.getChildLayoutPosition(child);
            if (position == 0) {
                if (isIncludeTop) {
                    final int top = child.getTop() - params.topMargin - mTopEdgeSpace;
                    final int bottom = top + mTopEdgeSpace;
                    c.drawRect(left, top, right, bottom, mPaint);
                }
                final int top = child.getBottom() + params.bottomMargin;
                final int bottom = top + mRectSpace;
                c.drawRect(left, top, right, bottom, mPaint);
            } else if (position == itemCount - 1) {
                if (isIncludeBottom) {
                    final int top = child.getBottom() + params.bottomMargin;
                    final int bottom = top + mBottomEdgeSpace;
                    c.drawRect(left, top, right, bottom, mPaint);
                }
            } else {
                final int top = child.getBottom() + params.bottomMargin;
                final int bottom = top + mRectSpace;
                c.drawRect(left, top, right, bottom, mPaint);
            }
        }
        drawLeftOrRightSpace(c, parent);
    }

    public void drawLeftOrRightSpace(Canvas c, RecyclerView parent) {
        if (isIncludeLeft) {
            final int left = parent.getPaddingLeft();
            final int top = parent.getPaddingTop();
            final int right = left + mLeftEdgeSpace;
            final int bottom = parent.getHeight() - parent.getPaddingBottom();
            c.drawRect(left, top, right, bottom, mPaint);
        }
        if (isIncludeRight) {
            final int left = parent.getWidth() - parent.getPaddingRight() - mRightEdgeSpace;
            final int top = parent.getPaddingTop();
            final int right = left + mRightEdgeSpace;
            final int bottom = parent.getHeight() - parent.getPaddingBottom();
            c.drawRect(left, top, right, bottom, mPaint);
        }
    }

    private void drawListHorizontal(Canvas c, RecyclerView parent) {
        final int childCount = parent.getChildCount();
        int itemCount = Objects.requireNonNull(parent.getAdapter()).getItemCount();
        if (childCount == 0) return;

        final int top = isIncludeTop ? parent.getPaddingTop() + mTopEdgeSpace : parent.getPaddingTop();
        final int bottom = isIncludeBottom ? parent.getHeight() - parent.getPaddingBottom() - mBottomEdgeSpace : parent.getHeight() - parent.getPaddingBottom();

        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            int position = parent.getChildLayoutPosition(child);
            if (position == 0) {
                if (isIncludeLeft) {
                    final int left = child.getLeft() - params.leftMargin - mLeftEdgeSpace;
                    final int right = left + mLeftEdgeSpace;
                    c.drawRect(left, top, right, bottom, mPaint);
                }
                final int left = child.getRight() + params.rightMargin;
                final int right = left + mRectSpace;
                c.drawRect(left, top, right, bottom, mPaint);
            } else if (position == itemCount - 1) {
                if (isIncludeRight) {
                    final int left = child.getRight() + params.rightMargin;
                    final int right = left + mRightEdgeSpace;
                    c.drawRect(left, top, right, bottom, mPaint);
                }
            } else {
                final int left = child.getRight() + params.rightMargin;
                final int right = left + mRectSpace;
                c.drawRect(left, top, right, bottom, mPaint);
            }
        }
        drawTopOrBottomSpace(c, parent);
    }

    private void drawTopOrBottomSpace(Canvas c, RecyclerView parent) {
        if (isIncludeTop) {
            final int left = parent.getPaddingLeft();
            final int top = parent.getPaddingTop();
            final int right = parent.getWidth() - parent.getPaddingRight();
            final int bottom = top + mTopEdgeSpace;
            c.drawRect(left, top, right, bottom, mPaint);
        }
        if (isIncludeBottom) {
            final int left = parent.getPaddingLeft();
            final int top = parent.getHeight() - parent.getPaddingBottom() - mBottomEdgeSpace;
            final int right = parent.getWidth() - parent.getPaddingRight();
            final int bottom = top + mBottomEdgeSpace;
            c.drawRect(left, top, right, bottom, mPaint);
        }
    }

    private void drawGridSpace(Canvas canvas, RecyclerView parent) {
        GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager();
        int spanCount = Objects.requireNonNull(gridLayoutManager).getSpanCount();
        GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup();
        int childCount = parent.getChildCount();
        int top, bottom, left, right;
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            int position = parent.getChildLayoutPosition(child);
            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();

            int spanGroupIndex = spanSizeLookup.getSpanGroupIndex(position, spanCount);
            int spanSize = spanSizeLookup.getSpanSize(position);
            int spanIndex = spanSizeLookup.getSpanIndex(position, spanCount);
            // 画bottom分割线,如果没到达底部,绘制bottom
            top = child.getBottom() + layoutParams.bottomMargin;
            bottom = top + mRectSpace;
            left = child.getLeft() - layoutParams.leftMargin;
            right = child.getRight() + layoutParams.rightMargin + mRectSpace;
            canvas.drawRect(left, top, right, bottom, mPaint);
            // 画right分割线
            top = child.getTop() - layoutParams.topMargin;
            bottom = child.getBottom() + layoutParams.bottomMargin;
            left = child.getRight() + layoutParams.rightMargin;
            right = left + mRectSpace;
            canvas.drawRect(left, top, right, bottom, mPaint);
        }

        drawLeftOrRightSpace(canvas, parent);
        drawTopOrBottomSpace(canvas, parent);
    }

    public static class Builder {
        private Context context;
        private int orientation = VERTICAL;
        private int rectSpace;
        private int leftEdgeSpace;
        private int topEdgeSpace;
        private int rightEdgeSpace;
        private int bottomEdgeSpace;
        private boolean isIncludeLeft;
        private boolean isIncludeTop;
        private boolean isIncludeRight;
        private boolean isIncludeBottom;
        private int paintColor = Constants.COLOR.WHITE_SMOKE;

        public Builder(Context context) {
            this.context = context;
            rectSpace = DpUtils.dip2px(context, DEFAULT_SPACE);
            leftEdgeSpace = topEdgeSpace = rightEdgeSpace = bottomEdgeSpace = rectSpace;
        }

        public Context getContext() {
            return context;
        }

        public Builder setContext(Context mContext) {
            this.context = mContext;
            return this;
        }

        public int getOrientation() {
            return orientation;
        }

        public Builder setOrientation(int orientation) {
            this.orientation = orientation;
            return this;
        }

        public int getRectSpace() {
            return rectSpace;
        }

        public Builder setRectSpace(float rectSpace) {
            this.rectSpace = DpUtils.dip2px(context, rectSpace);
            return this;
        }

        public int getLeftEdgeSpace() {
            return leftEdgeSpace;
        }

        public Builder setLeftEdgeSpace(int leftEdgeSpace) {
            this.leftEdgeSpace = DpUtils.dip2px(context, leftEdgeSpace);
            return this;
        }

        public int getTopEdgeSpace() {
            return topEdgeSpace;
        }

        public Builder setTopEdgeSpace(int topEdgeSpace) {
            this.topEdgeSpace = DpUtils.dip2px(context, topEdgeSpace);
            return this;
        }

        public int getRightEdgeSpace() {
            return rightEdgeSpace;
        }

        public Builder setRightEdgeSpace(int rightEdgeSpace) {
            this.rightEdgeSpace = DpUtils.dip2px(context, rightEdgeSpace);
            return this;
        }

        public int getBottomEdgeSpace() {
            return bottomEdgeSpace;
        }

        public Builder setBottomEdgeSpace(int bottomEdgeSpace) {
            this.bottomEdgeSpace = DpUtils.dip2px(context, bottomEdgeSpace);
            return this;
        }

        public boolean isIncludeLeft() {
            return isIncludeLeft;
        }

        public Builder setIncludeLeft(boolean includeLeft) {
            this.isIncludeLeft = includeLeft;
            return this;
        }

        public boolean isIncludeTop() {
            return isIncludeTop;
        }

        public Builder setIncludeTop(boolean includeTop) {
            this.isIncludeTop = includeTop;
            return this;
        }

        public boolean isIncludeRight() {
            return isIncludeRight;
        }

        public Builder setIncludeRight(boolean includeRight) {
            this.isIncludeRight = includeRight;
            return this;
        }

        public boolean isIncludeBottom() {
            return isIncludeBottom;
        }

        public Builder setIncludeBottom(boolean includeBottom) {
            this.isIncludeBottom = includeBottom;
            return this;
        }

        public int getPaintColor() {
            return paintColor;
        }

        public Builder setPaintColor(int paintColor) {
            this.paintColor = paintColor;
            return this;
        }

        public CommonDividerItemDecoration build() {
            return new CommonDividerItemDecoration(this);
        }
    }

    /**
     * 判断是不是第一行
     *
     * @param pos       item index in adapter
     * @param spanCount your grid spanCount
     * @return true or false
     */
    private boolean isFirstRow(int pos, int spanCount) {
        return (pos / spanCount) == 0;
    }

    /**
     * 判断是不是最后一行
     *
     * @param pos        item index in adapter
     * @param spanCount  your grid spanCount
     * @param childCount your total ItemCount
     * @return true or false
     */
    private boolean isLastRow(int pos, int spanCount, int childCount) {
        int ranger = childCount % spanCount;
        if (ranger == 0) {
            ranger = spanCount;
        }
        childCount = childCount - ranger;
        return pos >= childCount;
    }

    /**
     * 判断是不是第一列
     *
     * @param pos       item index in adapter
     * @param spanCount your grid spanCount
     * @return true or false
     */
    private boolean isFirsColumn(int pos, int spanCount) {
        return pos % spanCount == 0;
    }

    /**
     * 判断是不是最后一列
     *
     * @param pos       item index in adapter
     * @param spanCount your grid spanCount
     * @return true or false
     */
    private boolean isLastColumn(int pos, int spanCount) {
        return (pos + 1) % spanCount == 0;
    }
}

本文地址:https://blog.csdn.net/xielunyan666/article/details/107908480

《Recyclerview ItemDecoration 通用分割线.doc》

下载本文的Word格式文档,以方便收藏与打印。