今天对RecyclerView.ItemDecoration做了蛮多的理解,赶紧记下来,一直在思考分割线与item间的关系,后来模仿着做了很多的调整测试,才大概弄懂了。
这是一个分割线的绘制,通过multRecyclerView.addItemDecoration(new ItemDecoration(this));就可以将其显示出来。
public class ItemDecoration extends RecyclerView.ItemDecoration{
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
private Drawable mDivider;
public ItemDecoration(Context context){
final TypedArray typedArray = context.obtainStyledAttributes(ATTRS);
mDivider = typedArray.getDrawable(0);
typedArray.recycle();
}
@Override
public void onDraw(Canvas c, RecyclerView parent, State state) {
// TODO Auto-generated method stub
super.onDraw(c, parent, state);
drawVertical(c , parent);
}
private void drawVertical(Canvas c, RecyclerView parent) {
// TODO Auto-generated method stub
//recyclerview左边界+paddingleft后的位置
final int left = parent.getPaddingLeft();
//右边界-paddingright后的位置
final int right = parent.getWidth() - parent.getPaddingRight();
final int count = parent.getChildCount();
for(int i = 0 ; i < count ; i ++){
final View childView = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (LayoutParams) childView.getLayoutParams();
final int top = childView.getBottom() + params.bottomMargin ;
//top加上divider的高度
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left , top , right , bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
// TODO Auto-generated method stub
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
}
}
图:
这里面分成两个地方,一个是onDraw(),另一个则是getItemOffsets()。
首先我们在onDraw里去画分割线,然后在getItemOffsets里去设置item的显示(这里要作个说明,在这部分代码里是让item给分割线留出位置,而这个位置也刚好是分割线的高度。那么其实这个item的范围实际上是可以大于我们自己本身自己的chidView,做一些修改来看下:
以下只提供修改的代码,其它的没有说明则表示不变:
(1)outRect.set(0, 0, 0, 0);
这里我们可以看到没有分割线,当你不写getItemOffsets()方法的时候,它也是没有显示,那么这里其实是分割线通过onDraw()已经画好了,只是因为我们没有给分割线预留了空间,所以它被藏在了后面。
(2)outRect.set(100, 0, 0, 0);
所以我们试着往右移,从这里我们可以看到分割线实际是在后面的。
(3)outRect.set(100, 0, 0, 100);
outRect.set(100, 100, 0, 0);
先不管分割线,因为我们的分割线是设置固定在childView的下方的,不是根据item。从这些就可以看出,在getItemOffsets()里我们对item的尺寸进行了设置(我们要区分这里的item和我们自己设置的R.layout.item里的是有区别的。这里的childView就是我们自己设置的R.layout.item,而item就是这外层的整体。所以当我们在进行outRect.set(left,top ,right , bottom)的时候,就类似于在设置childView相对于item的padding。)。
(1)final int top = childView.getBottom() + params.bottomMargin + 50;
这里我们将分割线的top在原来上+50,那么它绘制出来的话就是在原来的基础上,往下移动50个像素。
那么我们可以进一步操作,来看的更明显些:
final int top = childView.getBottom() + params.bottomMargin + 360 ;
outRect.set(50, 0, 0, mDivider.getIntrinsicHeight());
我们先把childView往右移一下,这样我们就可以很明显的看出,top本来应该贴在item的下方显示,但现在我们修改成了往下360的地方出现。
(2)final int bottom = top + mDivider.getIntrinsicHeight() + 50;
分割线的宽度是根据top加上一个固定值来决定的,也就是bottom的值,现在我们+50,也就是它的宽度增加了50,所以我们可以从最底部看到分割线增加了50,而上面的只是因为被藏在了后面,我们看不到而已。同样我们可以放大的来看。
final int bottom = top + mDivider.getIntrinsicHeight() + 200;
outRect.set(50, 0, 0, mDivider.getIntrinsicHeight());
同样的我们将childView右移,然后把分割线+200,我们就可以看到,item的后面其实分割线大到已经有重叠了(深灰色部分)。
所以其实最后我想说的是,在这里分割线的出现,其实是通过调整item里的childView以腾出空间来将我们本来已经画好的分割线显示出来,它就是一个覆盖的关系,item覆盖在了分割线的上方,我们要让分割线显示出来,就要去调整getItemOffsets()。
参考与扩展:
深入理解 RecyclerView 系列之一:ItemDecoration
Android RecyclerView 使用完全解析 体验艺术般的控件