RecyclerView学习--自定义ItemDecoration

RecyclerView无法像ListView直接设置分割线,但是提供了ItemDecoration类来设置,有一个实现类DividerItemDecoration提供了一个简单的分隔线,如果想自定义可以继承ItemDecoration,参考DividerItemDecoration来写。

效果图,我是写了一个shape
1.主要实现方法

public class MyLinearDecoration extends RecyclerView.ItemDecoration {
	//绘制自定义的分隔线,这个绘制和item的View属于同一位面,分隔线太大会阻挡视图
	//这个绘制大小要配合getItemOffsets中设置的分隔线空间
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c,parent,state);
	}

    //设置分隔线的大小,留出画分隔线的空间
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
    }

    //Over是 在...之上的意思,所以他是在onDraw绘制位面的上一层进行绘制,他和onDraw相当于2层画布
	@Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
    }
}

2.具体的实现

public class MyLinearDecoration extends RecyclerView.ItemDecoration {
    Paint paint;
    Drawable drawable;
    Rect mBounds = new Rect();
    public MyLinearDecoration(Drawable drawable) {
        super();
        paint = new Paint();
        paint.setColor(Color.RED);
        this.drawable = drawable;
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c,parent,state);
        int right = 0;
        int left = 0;
        c.save();
        //这个if else是参照DividerItemDecoration,可以提高点性能,减少画布大小,
        //如果recyclerView设置了Padding,我们没必要获取整个画布,获取减去padding的
        //才是我们真正能够操作的画布
        if (parent.getClipToPadding()) {
            int top = parent.getPaddingTop();
            int bottom = parent.getPaddingBottom();
            left = parent.getPaddingLeft();
            right = parent.getWidth()-parent.getPaddingRight();
            c.clipRect(left,top,right,parent.getHeight() - bottom);
        }else{
            left = 0;
            right = parent.getWidth();
        }
        
        //下面的操作,遍历Item,为Item绘制想要的分隔线
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View view = parent.getChildAt(i);
            
            //获取这个Item的包含了Decoration和Margin的范围,相当于加上getItemOffsets设置的大小和Margin大小后,
            //这个Item的左,上,右,下的坐标
            parent.getDecoratedBoundsWithMargins(view, mBounds);
            
            //这个注释掉的是按照我自己的想法设置的绘制边界,测试也没问题,我从示例中得出结论是
            //mBounds得到的就是每个RecyclerView的Item加上间隔和margin后的最终所处的四个方位的坐标,
            //那么我们绘制Decoration的底部
            //就应该是mBounds.bottom,高度就应该是底部坐标减去分隔线的高度
			//final int bottom = mBounds.bottom;
            //final int top = mBounds.bottom - drawable.getIntrinsicHeight();
            
            //DividerItemDecoration中的示例是加了一个Math.round(view.getTranslationY()),这个获取的是这个View相对于他个
            //getTop的距离,我Debug查看了获取的值,一直为0,暂时没太明白这样写的意思。
            final int bottom = mBounds.bottom + Math.round(view.getTranslationY());
            final int top = bottom - drawable.getIntrinsicHeight();
            
            //这是我在构造器中传入的Drawable要绘制到的画布的范围
            drawable.setBounds(left, top, right, bottom);
            drawable.draw(c);
        }
        c.restore();
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        //这个设置的意思是,在Item的底部加上一段距离,让分隔线画在这个范围
        //不设置的话,分隔线会画到Item的视图上,造成重合
        //如果你的onDraw没有给出自己的实现,只是通过这个方法设置一块区域,那么也会
        //出现一段距离,背景色是这个界面的背景色
        outRect.bottom = drawable.getIntrinsicHeight();
    }
}

底部空出了这个Drawable高度的距离,也就是红色的部分

这个是垂直方向的LinearLayoutManager的绘制方式,如果是水平或者GridLayoutManager要注意考虑设置
间隔线范围的位置是底部还是右边
GridLayoutManager要注意边界的Item可能有的不需要加分隔,要注意。

有什么意见和错误欢迎提出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值