借用大神的框架为RecyclerView设置分割线

个人觉得RecyclerView的自定义分割线颇为复杂,于是在网上找到了一份个人感觉比较全面的框架。

首先是对应LinearLayoutManager的ItemDecoration,直接上代码

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.DimenRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * 对应LinearLayoutManager的ItemDecoration
 * 当设置滑动方向上有padding时有bug(例如VERTICAL时,设置上下padding)
 * Created by jph on 2016/12/14.
 */
public class LinearItemDecoration extends RecyclerView.ItemDecoration {

    private final Drawable mDivider;
    private final int mDividerSize;

    public LinearItemDecoration(Context context, @DrawableRes int drawRes, @DimenRes int sizeRes) {
        this(ContextCompat.getDrawable(context, drawRes), context.getResources().
                getDimensionPixelSize(sizeRes));
    }

    public LinearItemDecoration(@NonNull Drawable divider, int dividerSize) {
        mDivider = divider;
        mDividerSize = dividerSize;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left;
        int right;
        int top;
        int bottom;
        if (getOrientation(parent) == LinearLayoutManager.HORIZONTAL) {
            top = parent.getPaddingTop();
            bottom = parent.getHeight() - parent.getPaddingBottom();
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View child = parent.getChildAt(i);
                if (!isAllowShowDivider(child, parent)) {
                    continue;
                }
                RecyclerView.LayoutParams params =
                        (RecyclerView.LayoutParams) child.getLayoutParams();
                left = child.getRight() + params.rightMargin;
                right = left + mDividerSize;
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
        } else {
            left = parent.getPaddingLeft();
            right = parent.getWidth() - parent.getPaddingRight();
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View child = parent.getChildAt(i);
                if (!isAllowShowDivider(child, parent)) {
                    continue;
                }
                RecyclerView.LayoutParams params =
                        (RecyclerView.LayoutParams) child.getLayoutParams();
                top = child.getBottom() + params.bottomMargin;
                bottom = top + mDividerSize;
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                               RecyclerView.State state) {
        if (!isAllowShowDivider(view, parent)) {
            outRect.set(0, 0, 0, 0);
            return;
        }
        if (getOrientation(parent) == LinearLayoutManager.HORIZONTAL) {
            outRect.set(0, 0, mDividerSize, 0);
        } else {
            outRect.set(0, 0, 0, mDividerSize);
        }
    }

    private int getOrientation(RecyclerView parent) {
        if (parent.getLayoutManager() == null) {
            throw new NullPointerException("Must set LayoutManager to RecyclerView");
        }
        if (!(parent.getLayoutManager() instanceof LinearLayoutManager)) {
            throw new IllegalArgumentException("Invalid LayoutManager for this ItemDecoration, " +
                    "please set LinearLayoutManager.");
        }

        return ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
    }

    /**
     * 是否显示分割
     *
     * @param view
     * @param parent
     * @return
     */
    private boolean isAllowShowDivider(View view, RecyclerView parent) {
        return isAllowShowDivider(parent.getChildAdapterPosition(view), parent);
    }

    /**
     * 子类可控制是否显示分割
     *
     * @param position
     * @param parent
     * @return
     */
    protected boolean isAllowShowDivider(int position, RecyclerView parent) {
        if (position == parent.getAdapter().getItemCount() - 1) {
            //末尾不显示分割
            return false;
        }
        return true;
    }
}
另一个是针对GridLayoutManager的ItemDecoration

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.DimenRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * 针对GridLayoutManager的分割线
 * (暂未支持跨行)
 * Created by jph on 2016/12/14.
 */
public class GridItemDecoration extends RecyclerView.ItemDecoration {

    private Drawable mHorizontalDivider;//横向的分割线
    private Drawable mVerticalDivider;//纵向的分割线
    private int mDividerWidth;
    private int mDividerHeight;
    private int mUnderLayerOrientation = GridLayoutManager.HORIZONTAL;//横向还是纵向的分割线在下,因为有重叠部分

    public GridItemDecoration(Context context, @DrawableRes int drawRes,
                              @DimenRes int dividerSizeRes) {
        this(ContextCompat.getDrawable(context, drawRes), context.getResources().
                getDimensionPixelSize(dividerSizeRes));
    }

    public GridItemDecoration(Context context, @DrawableRes int drawRes,
                              @DimenRes int dividerWidthRes, @DimenRes int dividerHeightRes) {
        this(ContextCompat.getDrawable(context, drawRes), context.getResources().
                getDimensionPixelSize(dividerWidthRes), context.getResources().
                getDimensionPixelSize(dividerHeightRes));
    }

    public GridItemDecoration(Context context, @DrawableRes int horizontalDrawRes,
                              @DrawableRes int verticalDrawRes, @DimenRes int dividerWidthRes,
                              @DimenRes int dividerHeightRes) {
        this(ContextCompat.getDrawable(context, horizontalDrawRes), ContextCompat.getDrawable(
                context, verticalDrawRes), context.getResources().getDimensionPixelSize(
                dividerWidthRes), context.getResources().getDimensionPixelSize(dividerHeightRes));
    }

    public GridItemDecoration(@NonNull Drawable divider, int dividerSize) {
        this(divider, dividerSize, dividerSize);
    }

    public GridItemDecoration(@NonNull Drawable divider, int dividerWidth, int dividerHeight) {
        this(divider, divider, dividerWidth, dividerHeight);
    }

    public GridItemDecoration(@NonNull Drawable horizontalDivider,
                              @NonNull Drawable verticalDivider, int dividerWidth,
                              int dividerHeight) {
        mHorizontalDivider = horizontalDivider;
        mVerticalDivider = verticalDivider;
        mDividerWidth = dividerWidth;
        mDividerHeight = dividerHeight;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mUnderLayerOrientation == GridLayoutManager.HORIZONTAL) {
            drawHorizontal(c, parent, state);
            drawVertical(c, parent, state);
        } else {
            drawVertical(c, parent, state);
            drawHorizontal(c, parent, state);
        }
    }

    private void drawHorizontal(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left;
        int right;
        int top;
        int bottom;
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params =
                    (RecyclerView.LayoutParams) child.getLayoutParams();
            left = child.getRight() + params.rightMargin;
            right = left + mDividerWidth;
            top = child.getTop();
            bottom = child.getBottom() + mDividerHeight;
            mHorizontalDivider.setBounds(left, top, right, bottom);
            mHorizontalDivider.draw(c);
        }
    }

    private void drawVertical(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left;
        int right;
        int top;
        int bottom;
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params =
                    (RecyclerView.LayoutParams) child.getLayoutParams();
            top = child.getBottom() + params.bottomMargin;
            bottom = top + mDividerHeight;
            left = child.getLeft();
            right = child.getRight() + mDividerWidth;
            mVerticalDivider.setBounds(left, top, right, bottom);
            mVerticalDivider.draw(c);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                               RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (getOrientation(parent) == GridLayoutManager.VERTICAL) {
            getVerticalItemOffsets(outRect, view, parent, state);
        } else {
            getHorizontalItemOffsets(outRect, view, parent, state);
        }
    }

    private void getVerticalItemOffsets(Rect outRect, View view, RecyclerView parent,
                                        RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view);
        int spanCount = getSpanCount(parent);
        GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager();

        outRect.top = 0;
        if (isAllowShowDivider(position, parent)) {
            outRect.bottom = mDividerHeight;
        } else {
            outRect.bottom = 0;
        }

        int parentWidth = parent.getWidth();
        //每个item实际显示的宽度
        int itemContentWidth = (parentWidth - (spanCount - 1) * mDividerWidth) / spanCount;
        //每个item中预留出的边距总宽度,可能是单边有边距,可能是双边有边距
        int itemSpacingWidth = parentWidth / spanCount - itemContentWidth;

        int spanIndex = gridLayoutManager.getSpanSizeLookup().getSpanIndex(position,
                spanCount);
        outRect.left = spanIndex * (mDividerWidth - itemSpacingWidth);
        int realItemIndexInGroup = spanIndex + gridLayoutManager.getSpanSizeLookup()
                .getSpanSize(position) - 1;//算上跨度的index
        outRect.right = (realItemIndexInGroup + 1) * itemSpacingWidth -
                realItemIndexInGroup * mDividerWidth;
    }

    private void getHorizontalItemOffsets(Rect outRect, View view, RecyclerView parent,
                                          RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view);
        int spanCount = getSpanCount(parent);
        GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager();

        outRect.left = 0;
        if (isAllowShowDivider(position, parent)) {
            outRect.right = mDividerWidth;
        } else {
            outRect.right = 0;
        }

        int parentHeight = parent.getHeight();
        //每个item实际显示的宽度
        int itemContentHeight = (parentHeight - (spanCount - 1) * mDividerHeight) / spanCount;
        //每个item中预留出的边距总宽度,可能是单边有边距,可能是双边有边距
        int itemSpacingHeight = parentHeight / spanCount - itemContentHeight;

        int spanIndex = gridLayoutManager.getSpanSizeLookup().getSpanIndex(position,
                spanCount);
        outRect.top = spanIndex * (mDividerHeight - itemSpacingHeight);
        int realItemIndexInGroup = spanIndex + gridLayoutManager.getSpanSizeLookup()
                .getSpanSize(position) - 1;//算上跨度的index
//        int realItemIndexInGroup = position % mSpanCount;
        outRect.bottom = (realItemIndexInGroup + 1) * itemSpacingHeight -
                realItemIndexInGroup * mDividerHeight;
    }

    /**
     * 是否在最后一行/列
     *
     * @param position
     * @param parent
     * @return
     */
    private boolean isInLastGroup(int position, RecyclerView parent) {
        int spanCount = getSpanCount(parent);
        GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager();
        GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup();
        return spanSizeLookup.getSpanGroupIndex(parent.getAdapter().getItemCount() - 1, spanCount)
                == spanSizeLookup.getSpanGroupIndex(position, spanCount);
    }

    /**
     * 得到总共多少行/列
     *
     * @param parent
     * @return
     */
    private int getGroupCount(RecyclerView parent) {
        if (parent == null || parent.getLayoutManager() == null || parent.getAdapter() == null) {
            return 0;
        }
        if (parent.getAdapter().getItemCount() == 0) {
            return 0;
        }
        GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager();
        return gridLayoutManager.getSpanSizeLookup().getSpanGroupIndex(parent.getAdapter()
                .getItemCount() - 1, getSpanCount(parent)) + 1;
    }

    private int getOrientation(RecyclerView parent) {
        checkLayoutManager(parent);
        return ((GridLayoutManager) parent.getLayoutManager()).getOrientation();
    }

    private int getSpanCount(RecyclerView parent) {
        checkLayoutManager(parent);
        return ((GridLayoutManager) parent.getLayoutManager()).getSpanCount();
    }

    private void checkLayoutManager(RecyclerView parent) {
        if (parent.getLayoutManager() == null) {
            throw new NullPointerException("Must set LayoutManager to RecyclerView");
        }
        if (!(parent.getLayoutManager() instanceof GridLayoutManager)) {
            throw new IllegalArgumentException("Invalid LayoutManager for this ItemDecoration, " +
                    "please set GridLayoutManager.");
        }
    }

    /**
     * 子类可控制是否显示分割
     *
     * @param position
     * @param parent
     * @return
     */
    protected boolean isAllowShowDivider(int position, RecyclerView parent) {
        if (isInLastGroup(position, parent)) {
            //末尾不显示分割
            return false;
        }
        return true;
    }

    /**
     * 横向还是纵向的分割线在下,因为有重叠部分
     *
     * @param orientation
     */
    public void setUnderLayer(int orientation) {
        mUnderLayerOrientation = orientation;
    }
}
上面不管是线性布局还是网格布局,他们的构造方法都是一样的,就以网格布局的第一个构造函数来看public GridItemDecoration(Context context, @DrawableRes int drawRes,@DimenRes int dividerSizeRes)第一个参数不说了,第二个参数是指你自定义的divider的样式(注意:一定要把改文件放在drawable文件夹目录下),第三个是指divider的宽度(注意:一定得在value目录下的dimens里面设置值,然后再引用),设置值如下
<dimen name="dividersize">5dp</dimen>
调用时直接引用
mRecyclerView = (RecyclerView) findViewById(R.id.recycler);
        mRecyclerView.setLayoutManager(new GridLayoutManager(this,4));
        mRecyclerView.addItemDecoration(new GridItemDecoration(this,R.drawable.divider_bg,R.dimen.dividersize));
        mRecyclerView.setAdapter(mAdapter = new MyRecyclerAdapter(mDatas,this));

到这儿,所有关于分割线的工程就完毕了,最后,附上大神的源代码地址:https://github.com/happyjosh/XXXRecyclerViewDivider

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值