RecyclerView ItemDecoration 完全解析

本文详细解析了RecyclerView中的ItemDecoration,介绍了如何使用系统提供的DividerItemDecoration,以及如何自定义ItemDecoration,包括getItemOffsets()、onDraw()和onDrawOver()的方法实现,展示了如何创建横线、竖直进度分割线等效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们都知道,使用 RecyclerView 时 ,我们不能像 ListView 那样通过 setDivider() 的方式来设置分割线,好在 Android 为我们提供了定制性更强的 ItemDecoration 来为 RecyclerView 设置分割线。

什么是 ItemDecoration ?

顾名思义 ItemDecoration 就是 Item 的装饰,我们可以在 Item 的上下左右添加自定义的装饰,比如 横线,图案。同时系统已经为我们提供了一个 DividerItemDecoration, 如果这个 DividerItemDecoration 不满足我们的需求,我们就可以通过自定义 ItemDecoration 来实现了。

下面我们看下系统的 DividerItemDecoration :

DividerItemDecoration(系统提供)

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

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

效果:

如果想要修改 DividerItemDecoration 的颜色和高度,可以调用它的 setDrawable(drawable) 设置一个 Drawable 对象

// MainActivity.java
DividerItemDecoration decoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
Drawable dividerDrawable = getResources().getDrawable(R.drawable.drawable_divider);
decoration.setDrawable(dividerDrawable);
recyclerView.addItemDecoration(decoration);

// res/drawable/drawable_divider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    android:shape="rectangle">
    <!-- 渐变色 -->
    <gradient
        android:angle="135"
        android:centerColor="#4CAF50"
        android:endColor="#2E7D32"
        android:startColor="#81C784"
        android:type="linear" />

    <size android:height="1dp" />
</shape>

效果:

自定义 ItemDecoration

如果上述 DividerItemDecoration 不能满足我们的需求,那么我们就可以自定义 ItemDecoration ,ItemDecoration 的自定义主要需要重写以下三个方法:

/**
 * 自定义 ItemDecoration
 */
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
   
   

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

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

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

getItemOffsets() 主要作用是在 item 的四周留下边距,效果和 margin 类似,item 的四周留下边距后,我们就可以通过 onDraw() 在这个边距上绘制了。

public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) 

(1) 参数 Rect outRect : 表示 item 的上下左右所留下的边距。其中 outRect 的 left, top,right,bottom 即为 item 四周留下的边距的距离,默认都为 0 ;示意图如下:

getOffsets

(2) 参数 View view : 指当前 item 的 View 对象;

(3) 参数 RecyclerView parent : 指 RecyclerView 本身;

(4) RecyclerView.State state : 指 RecyclerView 当前的状态;

1.1 getItemOffsets() 应用例子:

既然 getItemOffsets(Rect outRect) 方法可以设置 item 四周的边距大小,那就可以设置 recyclerview 背景色和 item 四周的边距,使得 item 四周的边距透出 recyclerview 背景色来达到分割线的目的。

当然 item 的背景色需要和 recyclerview 的背景色不一致才有效果;

首先将 recyclerview 的背景色设置为 colorAccent 红色, 将 item 的背景色设置为 白色:

<!--- activity_main.xml -----> 
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorAccent" />

</android.support.constraint.ConstraintLayout>
<!--- item_recycler.xml -----> 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="#fff"
    android:gravity="center_vertical"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center_vertical" />

</LinearLayout>

然后继承 ItemDecoration 类,重写 getOffsets() 方法,将 outRect 的上边距 top 设置为 10px;

/**
 * 自定义 ItemDecoration
 */
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
   
   

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

最后将这个 LinearItemDecoration 添加到 RecyclerView 中:

LinearItemDecoration decoration = new LinearItemDecoration();
recyclerView.addItemDecoration(decoration);

效果如下(下方的红色是 因为RecyclerView 高度为 match_parent ,但 item 数据只有 5 条):

从效果图可以看出:每一个 item 的 顶部都有一个红色的背景线,包括第一个 item 顶部也有(怎么解决呢?见 2.1 节详解)

同理,我们可以设置为 底部 10px,左侧 20px ,右侧 40px;

public class LinearItemDecoration extends RecyclerView.ItemDecoration {
   
   

    @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 = 10;
        outRect.left = 20;
        outRect.right = 40;
    }
}

效果:

可以看到:每个 item 的左测,底部,右侧都有了间距,露出了 RecyclerView 的背景色了。

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

onDraw() 函数中的 parent , state 参数和 getItemOffsets() 方法中的参数含义是一样的,canvas 参数是 getItemOffsets() 函数所留下的左右上下的空白区域对应的 Canvas 画布对象。我们可以在这个区域中利用 Paint 画笔绘制任何图形。

比如在 item 左侧绘制一个 空心圆。

/**
 * 自定义 ItemDecoration
 */
public class LinearItemDecoration extends RecyclerView.ItemDecoration {
   
   

    private static final String TAG = "LinearItemDecoration";
    private Paint paint;

    public LinearItemDecoration() {
   
   
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
   
   
        super.getItemOffsets(outRect, view, parent, state);
        Log.e(TAG, "getItemOffsets: " );
        outRect.bottom = 10;
        outRect.left = 100;
        outRect.right = 40;
    }

    @Override
    public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
   
   
        super.onDraw(canvas, parent, state);
        Log.e(TAG, "onDraw: ");
        for (int i = 0; i < parent.getChildCount(); i++) {
   
   
            View childView = parent.getChildAt(i);
            canvas.<
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值