一、前言

毫无疑问,RecyclerView 是 Android 中最重要的系统组件之一,它的出现就是为了高效代替 ListView 和 GridView。

今天,我们来讲讲 RecyclerView 中的静态内部类 ItemDecoration。顾名思义 ItemDecoration 就是 Item 的装饰,我们可以在 Item 的上下左右添加自定义的装饰,从而丰富 Item 的 UI 效果。

二、RecyclerView 基础知识

我们都知道 RecyclerView 里面就是一个又一个的 Item,但是其实这些 Item 外面包裹着一个矩形,只是我们再使用 RecyclerView 的时候 Left、Right、Top 和 Bottom 默认都是 0,所以我们看不到这些矩形,具体如下图所示:
Android RecyclerView ItemDecoration 类解析_第1张图片

三、DividerItemDecoration(系统提供)

我们都知道,使用 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 简单使用

不设置分割线,效果如下所示:

Android RecyclerView ItemDecoration 类解析_第2张图片

3.2、使用 DividerItemDecoration 设置分割线

DividerItemDecoration 的使用非常简单,只需添加下面代码即可:

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

具体效果如下所示:

Android RecyclerView ItemDecoration 类解析_第3张图片
一般情况下以上 RecyclerView 的基本用法便可以实现绝大多数需求,但是某些场景下却远远不够,特别是需要实现比较复杂的 UI 效果的时候,所以这时候就需要利用 ItemDecoration,接下来我们就学习一下 ItemDecoration 的具体使用。

四、ItemDecoration 源码

首先,我们来看一下 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);    }}

从源码中我们可以看出 ItemDecoration 类中就只有三个方法,分别是 onDraw()、onDrawOver() 和 getItemOffsets(),具体作用如下:

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

4.1、getItemOffsets()

getItemOffsets() 的作用就是设置 Item 的内嵌偏移长度,从上面我们已经知道,RecyclerView 的 Item 外面是包裹着一个矩形的,这个方法就是用来设置矩形与 Item 之间的间隔的。

具体使用:

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());

效果如下所示:(上下左右都设置了 100px 的偏移量)

Android RecyclerView ItemDecoration 类解析_第4张图片

4.2、onDraw()

onDraw() 的作用是通过 Canvas 对象绘制内容,需要注意的是 onDraw() 绘制会先于 Item 的绘制,所以如果在 onDraw() 中绘制的内容在 Item 边界内,就会被 Item 遮挡住,所以 onDraw() 一般会和 getItemOffsets() 结合一起使用,即在矩形与 Item 的间隔区域内绘制内容。

实例1:在左侧间隔区域绘制一个空心圆,并在下侧间隔区域绘制一个 20px 的红色分割线。

我们先来看效果:

Android RecyclerView ItemDecoration 类解析_第5张图片
具体代码如下所示:

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);        }    }

getItemOffsets() 是针对每个 item 都会执行一次,也就是说每个 item 的 outRect 可以设置为不同值,但是 onDraw() 是针对 ItemDecoration 的,不是针对 item 的,只执行一次。所以我们在 onDraw() 中绘制的时候,需要遍历每个 item 进行绘制。

4.2、onDrawOver()

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

实例2:在实例1的基础上,绘制一个角标到 Item 上。

我们先来看效果:

Android RecyclerView ItemDecoration 类解析_第6张图片
具体代码如下所示:

@Overridepublic 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);        }    }}

五、小结

自定义 ItemDecoration 通常要根据需要,复写它的 3 个方法。

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

ItemDecoration 的作用远不止以上这么一点,我这里只是简单的介绍了下 ItemDecoration 中三个方法的使用,从而使得 RecyclerView 中的 Item 的 UI 更加丰富。

更多相关文章

  1. Android实现动态自动匹配输入内容功能
  2. android EditText 实时监听输入框的内容
  3. Android - AutoCompleteTextView (输入框动态匹配内容)
  4. Android 使用ContentProvider(内容提供者)共享数据
  5. android 浏览器 内容区 内嵌 scroll 不能滚动解决
  6. android之内容提供者解析
  7. Android 禁止屏幕旋转 & 旋转屏幕时保持Activity内容

随机推荐

  1. Mysql更换MyISAM存储引擎为Innodb的操作
  2. MACOS中忘记MySQL root密码的解决方案
  3. Mysql 5.7.17忘记密码怎么办
  4. mysql 行转列和列转行实例详解
  5. MySql 5.7.17免安装配置教程详解
  6. 解决Mysql5.7.17在windows下安装启动时提
  7. 在win10系统下安装Mysql 5.7.17图文教程
  8. mysql表名忽略大小写配置方法详解
  9. mysql 5.7.17 安装教程 附MySQL服务无法
  10. Mysql占用过高CPU时的优化手段(必看)