前言
ItemDecoration是实现了在RecyclerView对Item控件的绘制操作,因为以前研究PickView源码的时候,它是基于View的onDraw来绘制的,当时我就想着怎么实现,在ViewGroup中去执行这个onDraw,来绘制一些布局,感觉这个给了我一些思路,因此分析了一下源码,记录一下。
不仅如此,这里还对接口的的使用,算是一种静态代理模式,自己也想模拟这种的使用方法,把一个固定的父类的绘制,再辅助以子类灵活的绘制,这种代码的模式,觉得让自己受益非浅,感觉它不同于适配者模式,也不是策略模式,希望以后在工作中把这种模式灵活的运用下来。
源码部分
一、初始化
final ArrayList<RecyclerView.ItemDecoration> mItemDecorations;
//初始化
this.mItemDecorations = new ArrayList();
二、添加和删除
//添加
public void addItemDecoration(@NonNull RecyclerView.ItemDecoration decor, int index) {
if (this.mLayout != null) {
this.mLayout.assertNotInLayoutOrScroll("Cannot add item decoration during a scroll or layout");
}
if (this.mItemDecorations.isEmpty()) {
this.setWillNotDraw(false);
}
if (index < 0) {
this.mItemDecorations.add(decor);
} else {
this.mItemDecorations.add(index, decor);
}
this.markItemDecorInsetsDirty();
this.requestLayout();
}
//删除
public void removeItemDecorationAt(int index) {
int size = this.getItemDecorationCount();
if (index >= 0 && index < size) {
//getItemDecorationAt 获取单个
this.removeItemDecoration(this.getItemDecorationAt(index));
} else {
throw new IndexOutOfBoundsException(index + " is an invalid index for size " + size);
}
}
public void removeItemDecoration(@NonNull RecyclerView.ItemDecoration decor) {
if (this.mLayout != null) {
this.mLayout.assertNotInLayoutOrScroll("Cannot remove item decoration during a scroll or layout");
}
this.mItemDecorations.remove(decor);
if (this.mItemDecorations.isEmpty()) {
this.setWillNotDraw(this.getOverScrollMode() == 2);
}
this.markItemDecorInsetsDirty();
this.requestLayout();
}
三、获取
@NonNull
public RecyclerView.ItemDecoration getItemDecorationAt(int index) {
int size = this.getItemDecorationCount();
if (index >= 0 && index < size) {
return (RecyclerView.ItemDecoration)this.mItemDecorations.get(index);
} else {
throw new IndexOutOfBoundsException(index + " is an invalid index for size " + size);
}
}
public int getItemDecorationCount() {
return this.mItemDecorations.size();
}
四、绘制,这个是ItemDecoration的重点
调用顺序,这里是分三层绘制的。
第一层:
在RecyclerView的onDraw中调用onDraw,实现接口子控件的绘制,经常会看到这种用法,静态代理模式,这里也是实现了对ViewGroup方法的绘制的补充,ViewGroup我们知道是直接修改的布局,对onDraw的运用几乎没有,这里确有使用。
在这里【onDraw】是在RecyclerView的【onDraw】中调用的,是不同于ItemDecoration的【onDrawOver】方法的,它是绘制的会被RecyclerView的子View遮挡的,因为最先绘制,所以在最下方。
public void onDraw(Canvas c) {
super.onDraw(c);
int count = this.mItemDecorations.size();
for(int i = 0; i < count; ++i) {
((RecyclerView.ItemDecoration)this.mItemDecorations.get(i)).onDraw(c, this, this.mState);
}
}
第二层:
绘制RecyclerView的子控件
第三层:在RecycleView的【draw】方法中调用这个方法,实现了代理模式,在ViewGroup绘制时,实现了自定义控件的绘制,其中【onDrawOver】绘制的是不会被覆盖的视图。因为最后绘制,所以在最上方。
int count = this.mItemDecorations.size();
for(int i = 0; i < count; ++i) {
((RecyclerView.ItemDecoration)this.mItemDecorations.get(i)).onDrawOver(c, this, this.mState);
}
这里面,可以看出onDraw和onDrawOver的区别,是绘制顺序的不同,所以造成显示的内容不同。
五、滚动绘制
在scrollByInternal中调用,scrollByInternal是在Recycleview滚动时调用的,滚动时需要刷新子控件的布局
if (!this.mItemDecorations.isEmpty()) {
this.invalidate();
}
六、ViewFlinger子线程中绘制
if (!RecyclerView.this.mItemDecorations.isEmpty()) {
RecyclerView.this.invalidate();
}
七、公共方法,强制刷新布局
public void invalidateItemDecorations() {
if (this.mItemDecorations.size() != 0) {
if (this.mLayout != null) {
this.mLayout.assertNotInLayoutOrScroll
("Cannot invalidate item decorations during a scroll or layout");
}
this.markItemDecorInsetsDirty();
this.requestLayout();
}
}
参考:
View 的onDraw和Draw的区别: https://blog.csdn.net/qq_25711251/article/details/51655162
RecycyleView的Item的分析:https://blog.csdn.net/weixin_36709064/article/details/82078813