关于android:Android-RecyclerView-ItemDecoration-类解析

39次阅读

共计 5345 个字符,预计需要花费 14 分钟才能阅读完成。

一、前言

<font face = 黑体 > 毫无疑问,RecyclerView 是 Android 中最重要的零碎组件之一,它的呈现就是为了高效代替 ListView 和 GridView。

<font face = 黑体 > 明天,咱们来讲讲 RecyclerView 中的动态外部类 ItemDecoration。顾名思义 ItemDecoration 就是 Item 的装璜,咱们能够在 Item 的上下左右增加自定义的装璜,从而丰盛 Item 的 UI 成果。

二、RecyclerView 基础知识

<font face = 黑体 > 咱们都晓得 RecyclerView 外面就是一个又一个的 Item,然而其实这些 Item 里面包裹着一个矩形,只是咱们再应用 RecyclerView 的时候 Left、Right、Top 和 Bottom 默认都是 0,所以咱们看不到这些矩形,具体如下图所示:

三、DividerItemDecoration(零碎提供)

<font face = 黑体 > 咱们都晓得,应用 RecyclerView 时,咱们不能像 ListView 那样通过 setDivider() 的形式来设置分割线,然而零碎曾经为咱们提供了一个 DividerItemDecoration 类来设置分割线,这个类就是继承 RecyclerView.ItemDecoration,咱们来看下源码:

public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
    public static final int VERTICAL = LinearLayout.VERTICAL;

    private static final String TAG = "DividerItem";
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
    ... ...
    ... ...

3.1、RecyclerView 简略应用

<font face = 黑体 > 不设置分割线,成果如下所示:

3.2、应用 DividerItemDecoration 设置分割线

<font face = 黑体 >DividerItemDecoration 的应用非常简单,只需增加上面代码即可:

DividerItemDecoration decoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
recyclerView.addItemDecoration(decoration);

<font face = 黑体 > 具体成果如下所示:


<font face = 黑体 > 个别状况下以上 RecyclerView 的根本用法便能够实现绝大多数需要,然而某些场景下却远远不够,特地是须要实现比较复杂的 UI 成果的时候,所以这时候就须要利用 ItemDecoration,接下来咱们就学习一下 ItemDecoration 的具体应用。

四、ItemDecoration 源码

<font face = 黑体 > 首先,咱们来看一下 ItemDecoration 的源码,这里的源码曾经把正文和三个曾经被弃用的办法去掉了,具体如下所示:

public abstract static class ItemDecoration {public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull State state) {onDraw(c, parent);
    }
    
    public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent,  @NonNull State state) {onDrawOver(c, parent);
    }

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

<font face = 黑体 > 从源码中咱们能够看出 ItemDecoration 类中就只有三个办法,别离是 onDraw()、onDrawOver() 和 getItemOffsets(),具体作用如下:

  • <font face = 黑体 >onDraw(): 在子视图上绘制内容,绘制图层在 Item 以下,所以如果绘制区域与 Item 区域相重叠,会被遮挡;
  • <font face = 黑体 >onDrawOver():同样是绘制内容,但与 onDraw() 的区别是,绘制图层在最上层;
  • <font face = 黑体 >getItemOffsets():设置 ItemView 的内嵌偏移长度。

4.1、getItemOffsets()

<font face = 黑体 >getItemOffsets() 的作用就是设置 Item 的内嵌偏移长度,从下面咱们曾经晓得,RecyclerView 的 Item 里面是包裹着一个矩形的,这个办法就是用来设置矩形与 Item 之间的距离的。

<font face = 黑体 > 具体应用:

public class RectItemDecoration extends RecyclerView.ItemDecoration {

    // 参数阐明:// 1. outRect:全为 0 的 Rect(包含着 Item)// 2. view:RecyclerView 中的 视图 Item
    // 3. parent:RecyclerView 自身
    // 4. state:状态
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        // 4 个参数别离对应左(Left)、上(Top)、右(Right)、下(Bottom)// 上述语句代表:左、右、上和下偏移长度 =100px
        outRect.set(100, 100, 100,100);
    }
}
// 用自定义分割线类设置分割线
recyclerView.addItemDecoration(new RectItemDecoration());

<font face = 黑体 > 成果如下所示:(上下左右都设置了 100px 的偏移量)

4.2、onDraw()

<font face = 黑体 >onDraw() 的作用是通过 Canvas 对象绘制内容,须要留神的是 onDraw() 绘制会先于 Item 的绘制,所以如果在 onDraw() 中绘制的内容在 Item 边界内,就会被 Item 遮挡住,所以 onDraw() 个别会和 getItemOffsets() 联合一起应用,即在矩形与 Item 的距离区域内绘制内容。

<font face = 黑体 > 实例 1 :在左侧距离区域绘制一个空心圆,并在下侧距离区域绘制一个 20px 的红色分割线。

<font face = 黑体 > 咱们先来看成果:


<font face = 黑体 > 具体代码如下所示:

public class CircleRectDecoration extends RecyclerView.ItemDecoration {

    private Paint colorPaint;
    private Paint dividerPaint;
    
    // 初始化
    public RectItemDecoration() {colorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        colorPaint.setColor(Color.BLUE);
        colorPaint.setStyle(Paint.Style.STROKE);
        colorPaint.setStrokeWidth(5);

        dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        dividerPaint.setColor(Color.RED);
        dividerPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {outRect.set(100, 0, 0, 20);
    }

    @Override
    public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {super.onDraw(canvas, parent, state);
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        // 须要遍历每个 Item 进行绘制
        for (int i = 0; i < parent.getChildCount(); i++) {View childView = parent.getChildAt(i);
            int leftItemWidth = layoutManager.getLeftDecorationWidth(childView);
            int bottomItemHeight = layoutManager.getBottomDecorationHeight(childView);
            int left = leftItemWidth / 2;
            canvas.drawCircle(left, childView.getTop() + childView.getHeight() / 2, 20, colorPaint);
            // getItemOffsets() 中的设置的是 bottom = 20px; 所以在 drawRect 时,top 为 childView.getBottom, bottom 为 top + bottomDecorationHeight
            canvas.drawRect(new Rect(leftItemWidth, childView.getBottom(),
                    childView.getWidth() + leftItemWidth,
                    childView.getBottom() + bottomItemHeight), dividerPaint);
        }
    }

<font face = 黑体 >getItemOffsets() 是针对每个 item 都会执行一次,也就是说每个 item 的 outRect 能够设置为不同值,然而 onDraw() 是针对 ItemDecoration 的,不是针对 item 的,只执行一次。所以咱们在 onDraw() 中绘制的时候,须要遍历每个 item 进行绘制。

4.2、onDrawOver()

<font face = 黑体 >onDrawOver() 的作用与 onDraw() 相似,都是通过 Canvas 对象绘制内容,但与 onDraw() 的区别是:onDrawOver() 绘制是后于 onDraw() 的,所以绘制内容是不会被 Item 所遮挡的,反而 Item 会被 onDrawOver() 绘制的内容所遮挡。

<font face = 黑体 > 实例 2 :在实例 1 的根底上,绘制一个角标到 Item 上。

<font face = 黑体 > 咱们先来看成果:


<font face = 黑体 > 具体代码如下所示:

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

    int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {View view = parent.getChildAt(i);
        int index = parent.getChildAdapterPosition(view);
        float top = view.getTop();
        if (index < 3) {canvas.drawBitmap(mIcon, 120, top, flagPaint);
        }
    }
}

五、小结

<font face = 黑体 > 自定义 ItemDecoration 通常要依据须要,复写它的 3 个办法。

  • <font face = 黑体 >getItemOffsets 撑开 Item 上、下、左、右四个方向的空间;
  • <font face = 黑体 >onDraw 在 Item 内容之下绘制图形;
  • <font face = 黑体 >onDrawOver 在 Item 内容之上绘制图形。

<font face = 黑体 >ItemDecoration 的作用远不止以上这么一点,我这里只是简略的介绍了下 ItemDecoration 中三个办法的应用,从而使得 RecyclerView 中的 Item 的 UI 更加丰盛。

正文完
 0