欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RecycleView-自定义分割线-ItemDecoration

程序员文章站 2022-06-01 18:15:36
...

最近一段时间牙疼的不行,只能喝粥。鼓起勇气看了次牙医,发现2颗牙齿已经被虫子蛀到了神经,要把牙神经拔掉。现在想想真是后悔啊啊!!!各位程序员在写代码的同时,千万不要忘了好好呵护自己的牙齿!!千万!!

今天接到一个需求,大体就是实现一个网格布局,布局里元素有的左边没分割线,有的右边没分割线,有的分割线加粗……等等,总之分割线的分布完全没有规律,必须需要自定义来实现。琢磨了一下,发现RecycleView自带的itemDecoration可以完美的解决这个问题。

RecyclerView.ItemDecoration

利用RecycleView自带的这个类,可以完美的自定义各种分割线。只有你想不到的,没有itemDecoration做不到的!

这个类的核心方法有三个:

  • onDraw(Canvas c, RecyclerView parent, State state)
  • onDrawOver(Canvas c, RecyclerView parent, State state)
  • getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)

首先看一下onDraw(Canvas c, RecyclerView parent, State state)

public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
{
    //画水平分割线
    drawHorizontal(c, parent);
    //画垂直分割线
    drawVertical(c, parent);
}

onDraw这个方法中,主要来为每个子View画分割线,具体的做法可以计算出每个子View的(left,top,right,bottom) , 然后在这个区域内画上分割线。如果想做成listView的效果可以只画水平的分割线,如果想做成网格的布局可以同时实现纵向和横向的分割线。

来举个例子,实现一下纵向的分割线:

public void drawVertical(Canvas c, RecyclerView parent)
{
    //首先来获取子item的数量,来决定你画的分割线的数量
    final int childCount = parent.getChildCount();
    //然后做一个for循环来为你的子Item画上分割线
    for (int i = 0; i < childCount; i++)
    {
        final View child = parent.getChildAt(i);
        //拿到子View的布局属性
        final RecyclerView.LayoutParams params =       (RecyclerView.LayoutParams) child
                .getLayoutParams();
        //这里开始来设置分割线的区域
        final int top = child.getTop() - params.topMargin;
        final int bottom = child.getBottom() + params.bottomMargin;
        //我这里默认从item的右侧开始画,所以分割线的left区域我取了子View的Right + margin
        final int left = child.getRight() + params.rightMargin;
        //这里注意了,小伙伴们!mDivider.getIntrinsicWidth() 代表了分割线的宽度,你可以自己设比如50。也可以直接取mDivider的宽度。 mDivider是一个我已经画好的一个分割线drawble,很简单。因为通过drawble可以定义一下分割线的颜色,透明度等。十分的灵活
        final int right = left + mDivider.getIntrinsicWidth();
        if(i != 1){
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }
}

好了,以上就是纵向分割线的实现,很简单吧。横向分割线的实现也是同理。如果想做成一个万能的分割线,可以在构造中传入参数来决定是需要横向的还是纵向的还是网格的。

getItemOffsets

这个函数看了下网上说的,感觉都说的比较复杂。我这里就不做深入的分析了,简洁明了的帮助大家来理解下。

这个函数,3个参数:

  • Rect outRect
  • int itemPosition
  • RecyclerView parent

首先第一个参数,也是最重要的一个参数。先看以下4副图,分别是outRect不同参数下的表现。

RecycleView-自定义分割线-ItemDecoration

从图中可以看出,outRect(left,top,right,bottom) 实际上可以理解为对子View做了一次的padding,他代表分割线可以显示的区域。由于itemDecoration的分层是在parent层之上,子View层之下,即分层由下到上依次是paret < itemDecoration < 子View 。 而 getItemOffsets函数是来操作顶层的子View可以给itemDecoration显示的区域。
举个例子:
如图3 (50,50,0,50)代表了子View左上右分别可以给itemDecoration 50像素来展示,而右边即使你在onDraw中画了,也会被子View给盖住而展示不出来。

我在这里做了个有趣的实验,即我把子View的背景设成了透明,这个方法无论如何设置,都失效了。这正验证了我上面的理论,即子View的背景透明后,无论你怎么设置itemDecoration的显示区域,最上层的子View都无法将处于下层的itemDecoration给遮住。 有兴趣的朋友可以试一试。

最后来讲一讲onDrawOver()

onDrawOver

顾名思义这是绘制在最上层的画布,甚至比子View所绘制的画布还要顶层。

decoration 的 onDraw,child view 的 onDraw,decoration 的 onDrawOver,这三者是依次发生的。而由于 onDrawOver 是绘制在最上层的,所以它的绘制位置并不受限制(当然,decoration 的 onDraw 绘制范围也不受限制,只不过不可见),所以利用 onDrawOver 可以做很多事情,例如为 RecyclerView 整体顶部绘制一个蒙层,或者为特定的 item view 绘制蒙层。

好了,以上就是今天要分享的内容。总结一下,itemDecoration可以为你的RecycleView定制各种各样的分割线。当然这是最基础的用法,例如用最后提到的onDrawOver来实现蒙层等

最近一直在研究VPN,有时间要好好总结一下。