RecyclerView.ItemDecoration
decoration 英文意思:
英[ˌdekəˈreɪʃn] 美[ˌdɛkəˈreʃən] n. 装饰品; 装饰,装潢; 装饰图案,装饰风格; 奖章;
[例句]The decoration and furnishings had to be practical enough for a family home 房子的装潢和家具都必须很实用,适合家居生活。 [
其他] 复数:decorations
RecyclerView.ItemDecoration 装饰类,都装饰啥?
RecyclerView.ItemDecoration装饰的目标当然是RecyclerView里面每个item.
之前ListView有divier属性可以修改分隔线的样式
RecyclerView则是提供了
recyclerView.addItemDecoration()
看一下源码:

public static abstract class ItemDecoration { /** * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn before the item views are drawn, * and will thus appear underneath the views. * * @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView */ public void onDraw(Canvas c, RecyclerView parent, State state) { onDraw(c, parent); } /** * @deprecated * Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)} */ @Deprecated public void onDraw(Canvas c, RecyclerView parent) { } /** * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn after the item views are drawn * and will thus appear over the views. * * @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView. */ public void onDrawOver(Canvas c, RecyclerView parent, State state) { onDrawOver(c, parent); } /** * @deprecated * Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)} */ @Deprecated public void onDrawOver(Canvas c, RecyclerView parent) { } /** * @deprecated * Use {@link #getItemOffsets(Rect, View, RecyclerView, State)} */ @Deprecated public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { outRect.set(0, 0, 0, 0); } /** * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies * the number of pixels that the item view should be inset by, similar to padding or margin. * The default implementation sets the bounds of outRect to 0 and returns. * * <p> * If this ItemDecoration does not affect the positioning of item views, it should set * all four fields of <code>outRect</code> (left, top, right, bottom) to zero * before returning. * * <p> * If you need to access Adapter for additional data, you can call * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the * View. * * @param outRect Rect to receive the output. * @param view The child view to decorate * @param parent RecyclerView this ItemDecoration is decorating * @param state The current state of RecyclerView. */ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent); } }
会发现主要有下面三个方法:
1 2 3 4 5 6 | /**<br>* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.<br>* Any content drawn by this method will be drawn before the item views are drawn, * and will thus appear underneath the views. *<br>* @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView */ |
大概是说会在item画之前画些东西,会现在Item下面。那相当于是一个背景。
onDrawOver()
/** * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. * Any content drawn by this method will be drawn after the item views are drawn * and will thus appear over the views. * * @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView. */ public void onDrawOver(Canvas c, RecyclerView parent, State state) { onDrawOver(c, parent); }
will be drawn after the item views are drawn and will thus appear over the views.
很明白与上面的相对,会有Item画完之后去画,在浮在item内容上面。
getItemOffsets()
/** * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies * the number of pixels that the item view should be inset by, similar to padding or margin. * The default implementation sets the bounds of outRect to 0 and returns. * * <p> * If this ItemDecoration does not affect the positioning of item views, it should set * all four fields of <code>outRect</code> (left, top, right, bottom) to zero * before returning. * * <p> * If you need to access Adapter for additional data, you can call * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the * View. * * @param outRect Rect to receive the output. * @param view The child view to decorate * @param parent RecyclerView this ItemDecoration is decorating * @param state The current state of RecyclerView. */ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent); }
也说得很明白:similar to padding or margin.跟padding margin相似。给设置边距的。
从getItemOffsets()来开始实践
我们给recyclerview 加上背景以便观察。
<android.support.v7.widget.RecyclerView
android:id="@+id/rcv_qulitry"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f00">
</android.support.v7.widget.RecyclerView>
实现在自义定的decoration类
package com.lechang.fragment.decoration; import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.view.View; /** * Created by hongtao on 2017/11/17. */ public class MyDecoration extends RecyclerView.ItemDecoration { @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { outRect.left = 5; outRect.right = 5; outRect.bottom = 10; super.getItemOffsets(outRect, view, parent, state); } }
马上来用
recyclerView.addItemDecoration(new MyDecoration());
看看效果,嘿嘿,尼玛不是那么回事,怎么不起作用呢?
蒙逼了?
仔细看一下代码,方法调用了super.getItemOffsets(outRect, view, parent, state);再点进去看,
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
parent);
}
然后再调用了
@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}
看到没
outRect.set(0, 0, 0, 0);
给设置成0了。
那我们
outRect.left = 5;
outRect.right = 5;
outRect.bottom = 10;
设置的值就成白做了。
所以得把这个赋值放到super之后。
package com.lechang.fragment.decoration; import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.view.View; /** * Created by hongtao on 2017/11/17. */ public class MyDecoration extends RecyclerView.ItemDecoration { @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); //切记要先调super. outRect.left = 5; outRect.right = 5; outRect.bottom = 10; } }
这回可以了。
看一下效果:

红色底出来了。相当于padding .
只是底红露出,不能当分隔线,你非要用也行。
主要的还是要用ondraw把分隔线画出来。
下面来试ondraw().
原型:如下
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
这是一个回调的方法,给了一个画布,RecyclerView ,和RecyclerView.State
RecyclerView.State:给了下面三个状态
static final int STEP_START = 1;
static final int STEP_LAYOUT = 1 << 1;
static final int STEP_ANIMATIONS = 1 << 2;
意思是我们可以在这三个不同时期做不同的事,画不同的东西。有需求可以安排。
RecyclerView parent
既然是parent 那他的child都是个个item.
那整个方法的意思就是用Canvas c给每个item都画上装饰(分隔线)。
来一段代码:
package com.lechang.fragment.decoration; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.view.View; /** * Created by hongtao on 2017/11/17. */ public class MyDecoration extends RecyclerView.ItemDecoration { Paint dividerPaint; int dividerHeight = 3; public MyDecoration(Context context, int dividerHeight) { dividerPaint = new Paint(); dividerPaint.setColor(Color.BLACK); this.dividerHeight = dividerHeight; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); //切记要先调super. // outRect.left = 5; // outRect.right = 5; outRect.bottom = 20; } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State 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); } } }
outRect.bottom 给了 20的值,要是不给这个值,那将什么也看不到。因为是在item下层的;
最终效果:黑色线是onDraw结果,红是底

接下来看:
onDrawOver()方法效果
package com.lechang.fragment.decoration; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.support.v7.widget.RecyclerView; import android.view.View; /** * Created by hongtao on 2017/11/17. */ public class MyDecoration extends RecyclerView.ItemDecoration { Paint dividerPaint; int dividerHeight = 3; public MyDecoration(Context context, int dividerHeight) { dividerPaint = new Paint(); dividerPaint.setColor(Color.BLACK); this.dividerHeight = dividerHeight; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); //切记要先调super. // outRect.left = 5; // outRect.right = 5; // outRect.bottom = 20; } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State 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 onDraw(Canvas c, RecyclerView parent, RecyclerView.State 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); } } }
drawOver在上层画,所以不需要getItemOffsets配合。
至此,ImtemDecoration这个类基本我们就会用了。
如果对Item位置做一些逻辑处理,还能做出一些有意思的东西。接下来再写。告一段落。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)