一 前言

效果:
项目实践-自定义分割线(一)

目标就是:在聊天界面和个人信息这样的界面中,基本上就是一个RecyclerView了。如果不会自定义分割线,就只能很丑陋了w

本次的参考资料:
RecyclerView之ItemDecoration
(译文)RecyclerView之ItemDecoration由浅入深
深入理解 RecyclerView 系列之一:ItemDecoration

二 自定义ItemDecoration分割线上手

2.1 什么是ItemDecoration

我们之前写的RecyclerView设置分割线的方法如下:

recyclerView.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL));

然后粗略一查就知道,想要完成自定义分割线,需要的是自定义ItemDecoration。然后在MD官网里,我们看到标星号,写日期等也都是靠继承ItemDecoration之后完成。
ItemDecoration到底是什么?

直译:条目装饰,顾名思义,ItemDecoration是对Item起到了装饰作用,更准确的说是对item的周边起到了装饰的作用,通过下面的图应该能帮助你理解这话的含义。
项目实践-自定义分割线(一)
上图中已经说到了,
getItemOffsets()就是设置item周边的偏移量(也就是装饰区域的“宽度”)。
而onDraw()才是真正实现装饰的回调方法,通过该方法可以在装饰区域任意画画,
onDrawOver(),可以绘制在内容的上面,覆盖内容

2.2 getItemOffsets()方法

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, 
    						@NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
    }

参数解释:
outRect:

深入理解 RecyclerView 系列之一:ItemDecoration
getItemOffsets 中为 outRect 设置的4个方向的值,将被计算进所有 decoration 的尺寸中,而这个尺寸,被用来计算 RecyclerView 每个 item view 的大小(包括 item view 的宽高,padding,以及这个 insets)。

所以在2.1中说的,getItemOffsets()就是设置item周边的偏移量其实就是通过这个outRect来设置。它额外给每个item配置一个空间。
源码中是这样设置的:所以4个参数顺序也如下。左顶右底。但是却不是画矩形,不是画矩形。所以并非两对坐标。

    for (int i = 0; i < decorCount; i++) {
        mTempRect.set(0, 0, 0, 0);
        mItemDecorations.get(i).getItemOffsets(mTempRect, child, this, mState);
        insets.left += mTempRect.left;
        insets.top += mTempRect.top;
        insets.right += mTempRect.right;
        insets.bottom += mTempRect.bottom;
    }

关于insets:它是 LayoutManager 排列 child 时用的一个空间大小,说它是 child 的padding,确实不妥,child 所占用的空间大小,应该是宽高 + padding + insets。

尝试:

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, 
    							@NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.bottom = 30;
        //或者
        //outRect.set(0, 0, 0, 30);
    }

效果
项目实践-自定义分割线(一)

2.3 onDraw()方法

    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.onDraw(c, parent, state);

    }

这个方法参数有画布canvasRecyclerView。这个state我们暂时不管,官方文档的说法就是:

RecyclerView.State: The current state of RecyclerView。

看其他的参数:
项目实践-自定义分割线(一)
我迷茫的在于:这个画布canvas,具体指哪个地方呢?这个RecyclerView又要怎么用呢?
看参考文章的代码,其实蛮容易发现,canvas其实就和之前学习自定义View一样,指的就是整个画布。所以你需要的是获取每条分割线详细的位置。
而RecyclerView怎么用,它有一些方法是我们之前不需要用的,如parent.getChildCount() parent.getChildAt(i)等可以用来绘制。
我们很容易发现,因为它是一条线一条线绘制的,所以在特定的item处,可以使用特殊的绘制方法。比如设置一个标星区间。

public class MessageItemDecoration extends RecyclerView.ItemDecoration {
	//设置分割线的高度
    private int dividerHeight = 2;
    //画笔
    private Paint dividerPaint;

    public MessageItemDecoration() {
        dividerPaint = new Paint();
        dividerPaint.setColor(Color.BLUE);
    }
    @Override
    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.onDraw(c, parent, state);
        int childCount = parent.getChildCount();
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        for (int i = 0; i <= childCount - 1; i++) {
            View view = parent.getChildAt(i);
            float top = view.getBottom();
            float bottom = view.getBottom() + dividerHeight;
            c.drawRect(left, top, right, bottom, dividerPaint);
        }
    }
    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.set(0, 0, 0, dividerHeight);
    }
}

代码如上,效果如下:
项目实践-自定义分割线(一)
之后调整一下画线的位置,就可以实现一开始预期的效果了
项目实践-自定义分割线(一)

三 后记 关于ItemDecoration装饰效果

本来想的是,分成几个组,不同组之间的距离不同。后来发现不大行,因为它的getItemOffsets是对所有子项的。不过我们可以考虑在头像旁边加一个星星来表示置顶,而非一定要设置成灰色背景什么的。
同样,或许这样也可以设置信息的效果。

这个如果有需要的话,之后再来做自定义分割线(二)

相关文章:

  • 2021-07-19
  • 2021-06-08
  • 2021-09-20
  • 2022-03-05
  • 2021-11-02
  • 2021-07-24
  • 2022-12-23
猜你喜欢
  • 2021-04-25
  • 2021-04-13
  • 2021-10-14
  • 2021-10-27
  • 2022-12-23
  • 2021-05-31
相关资源
相似解决方案