美文网首页
RecyclerView 之ItemDecoration分隔线

RecyclerView 之ItemDecoration分隔线

作者: 木木禾木 | 来源:发表于2019-08-17 10:51 被阅读0次

RecyclerView 之ItemDecoration分隔线
RecyclerView 之ItemDecoration悬浮分隔线
RecyclerView 之ItemDecoration分隔线+悬浮分隔线


实现RecyclerView的分隔线,则要继承于RecyclerView.ItemDecoration,如下图所示:


RecyclerView.ItemDecoration

可以看出最主要的有三个方法:
(为易于分辨,设置RecyclerView背景色为绿色(#00cdcd),ItemView背景色为黄色(#cdcd00))

  1. void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)
    用以设置各个ItemView的内嵌偏移长度

当设置outRect.set(10, 20 , 30 , 40)时:

outRect.set(10, 20 , 30 , 40)
当设置outRect.left = 40时:
outRect.left = 40
那么,如果设置outRect.top = 1 (分割线高度为1px),再配合RecyclerView的背景色,是不就可以实现分割线了呢?
是的!但是这种方式过度依赖于RecyclerView的背景色,不够灵活,所以一般在onDraw中绘制分割线。
outRect.top = 1
  1. void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)
    先于ItemView绘制, 所以绘制图层在ItemView以下,所以如果绘制区域与ItemView区域相重叠,会被遮挡。

(将RecyclerView背景色为白色(#FFFFFF),ItemView背景色为透明(不设置背景色),分隔线颜色为红色)

    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.onDraw(c, parent, state);
        //获取RecyclerView的Child view的个数
        int childCount = parent.getChildCount();
        //遍历每个Item,分别获取它们的位置信息,然后再绘制对应的分割线
        for (int i = 0; i < childCount; i++) {
            View childView = parent.getChildAt(i);
            //绘制分割线
            c.drawRect(childView.getLeft(),
                    childView.getTop() - mDividerHeight,
                    childView.getRight(),
                    childView.getTop(),
                    mDividerPaint);
        }
    }
分隔线

当然,在不同的需求中,对分隔线的要求也很多,比如:

  1. RecyclerView添加几个header或footer(当然RecyclerView中没有header、footer,大家都是ItemView,这里便于描述),而header和footer部分不要分隔线;
  2. 分隔线不要贯穿整个RecyclerView,左右可设置margin;
    等等

附上完整代码抛砖引玉:

package com.test.wrapper.indexList;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class RecyclerItemDecoration extends RecyclerView.ItemDecoration {

    /**
     * RecyclerView 首部偏移量,前mOffsetStart个item不展示分隔线
     */
    private int mOffsetStart = 0;
    /**
     * RecyclerView 尾部偏移量,后mOffsetEnd个item不展示分隔线
     */
    private int mOffsetEnd = 0;
    /**
     * 分隔线 颜色、高度、左Margin、右Margin
     */
    private Paint mDividerPaint;
    private int mDividerColor = Color.parseColor("#cd0000");
    private int mDividerHeight = 1;
    private int mDividerLeftMargin = 0;
    private int mDividerRightMargin = 0;


    public RecyclerItemDecoration() {
        this.mDividerPaint = new Paint();
        //分隔线画笔
        mDividerPaint.setColor(mDividerColor);
        //抗锯齿
        mDividerPaint.setAntiAlias(true);
        //抗抖动
        mDividerPaint.setDither(true);
    }


    /**
     * 用以设置各个ItemView的内嵌偏移长度(inset)
     *
     * @param outRect Rect
     * @param view    View
     * @param parent  RecyclerView
     * @param state   RecyclerView.State
     */
    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        //获取子View在RecyclerView中位置
        int positionInRecycler = parent.getChildAdapterPosition(view);
        //判断当前位置是否需要 分隔View 或 分隔线 或 悬浮分隔
        if (isHasDivider(parent, positionInRecycler)) {
            outRect.top = mDividerHeight;
        }
    }

    /**
     * 在子视图上设置绘制范围,并绘制内容
     * 先于ItemView绘制, 所以绘制图层在ItemView以下,所以如果绘制区域与ItemView区域相重叠,会被遮挡
     *
     * @param c      Canvas
     * @param parent RecyclerView
     * @param state  RecyclerView.State
     */
    @Override
    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.onDraw(c, parent, state);

        //获取RecyclerView的Child view的个数
        int childCount = parent.getChildCount();
        //遍历每个Item,分别获取它们的位置信息,然后再绘制对应的分割线
        for (int i = 0; i < childCount; i++) {
            View childView = parent.getChildAt(i);
            if (isHasDivider(parent, childView)) {
                //绘制Divider宽度与ItemView宽度一致
                drawDivider(c, childView.getLeft() + mDividerLeftMargin,
                        childView.getTop() - mDividerHeight,
                        childView.getRight() - mDividerRightMargin,
                        childView.getTop());
            }
        }
    }

    //绘制分隔线
    private void drawDivider(Canvas c, float left, float top, float right, float bottom) {
        // 通过Canvas绘制矩形(分割线)
        c.drawRect(left, top, right, bottom, mDividerPaint);
    }

    //某个ItemView是否有分隔线
    private boolean isHasDivider(RecyclerView parent, View childView) {
        return isHasDivider(parent, parent.getChildAdapterPosition(childView));
    }

    /**
     * 某位置是否有分隔线
     * 子类可覆盖
     *
     * @param parent             RecyclerView
     * @param positionInRecycler RecyclerView中位置
     * @return boolean
     */
    protected boolean isHasDivider(RecyclerView parent, int positionInRecycler) {
        if (positionInRecycler <= mOffsetStart) {
            return false;
        }
        if (parent.getAdapter() != null) {
            if (positionInRecycler > parent.getAdapter().getItemCount() - mOffsetEnd - mOffsetStart) {
                return false;
            }
        }
        return true;
    }


}

使用:
每两个ItemView有一个分隔线(使用的RecyclerView有下拉刷新,相当于mOffsetStart = 1,故 (positionInRecycler - 1) ),分隔线左起30:

        mRecyclerView.addItemDecoration(object : RecyclerItemDecoration() {
            override fun isHasDivider(parent: RecyclerView?, positionInRecycler: Int): Boolean {
                return (positionInRecycler - 1) % 2 == 0
            }
        })
image.png

over ~

分隔线就到此结束了,下一节一起来撸悬浮分隔线
RecyclerView 之ItemDecoration悬浮分隔线

欢迎大家多多留言交流哈 ·_·

相关文章

网友评论

      本文标题:RecyclerView 之ItemDecoration分隔线

      本文链接:https://www.haomeiwen.com/subject/wclhsctx.html