导读
我们常常遇到设计要求RecycleView的自定义item的左右边距,中间均分,这时我们就需要自定义ItemDecoration,实现getItemOffsets方法,如何计算呢?
预备知识
- ItemDecoration解析(一) getItemOffsets
- 上条源码解析也可以略过,GridLayoutManager为了保证每个itemView在水平方向(orientation为vertical时)或者垂直方向(orientation为horizontal时)均分,那么必须让每个itemview的paddingleft + paddingRight ( orientation 为vertical 时 ) 或者 paddingTop + paddingBottom(orientation 为horizontal时)相等,当orientation为vertical时,我们需要在getItemOffsets方法中计算每个Item的PaddingLeft,以及PaddingRight,保证每个Item的paddingLeft+paddingRight相等,这样才能达到均分的目的。
实例分析
假如间距(space )= 14, spanCount = 4, 边距(edgeSpace)= 0
totalSpace = space * (itemCount-1) + edgeSpace * 2 = 42 // space总和
eachSpace = totalSpace / itemCount = 10.5 // item的leftPadding+rightPadding的和列出每一列的paddingLeft以及paddingRight:
colunm Left Right
0 edgeSpace(0) eachSpace-L0(10.5)
1 space-R0(3.5) eachSpace-L1 (7)
2 space-R1(7) eachSpace-R2(3.5)
3 space-R2(10.5) edgeSpace(0)
- 结论:Left是从0到eachSpace等差数列;Right用eachSpace-Left算出。
假如间距(space )= 14, spanCount = 4, 边距(edgeSpace)= 0
totalSpace = space * (itemCount-1) + edgeSpace * 2 = 66 //space总和
eachSpace = totalSpace / itemCount= 16.5 // item的leftPadding+rightPadding的和列出每一列的paddingLeft以及paddingRight:
colunm Left Right
0 edgeSpace(12) eachSpace-L0(4.5)
1 space-R0(9.5) eachSpace-L1 (7)
2 space-R1(7) eachSpace-R2(9.5)
3 space-R2(4.5) edgeSpace(12)
- 结论:Left是从edgeSpace到(eachSpace - edgeSpace)等差数列;Right用eachSpace-Left算出。
计算
- paddingLift是等差数列,公差计算公式:
1. 当边距为0时,d = eachSpace / (spanCount - 1);
2. 当边距不为0时,d = ( eachSpace - edgeSpace - edgeSpace ) / (spanCount - 1);
代码
public class BookAndProgramCoverItemDecoration implements ItemDecoration {
private int mEdgeSpace;//左右间距
private int mSpanCount;//列数
private int mEachSpace;//平均每个item可用间距(减去item自身宽度)
private int d;//公差
public BookAndProgramCoverItemDecoration(Context context, int spanCount) {
this(spanCount, Utils.dip2px(context, 15), Utils.getDeviceWidthPixels(context) - spanCount * CoverUtils.getBookCoverWidth(context));
}
public BookAndProgramCoverItemDecoration(int mSpanCount, int mEdgeSpace, int mTotalSpace) {
this.mSpanCount = mSpanCount;
this.mEdgeSpace = mEdgeSpace;
this.mEachSpace = mTotalSpace / mSpanCount;
d = (mEachSpace - mEdgeSpace - mEdgeSpace) / (mSpanCount - 1);
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
int column = itemPosition % mSpanCount;
outRect.left = column * d + mEdgeSpace;
outRect.right = mEachSpace - outRect.left;
}
}
/**
* Discription: RecyclerView均分,边距请设置padding
* Created by on 2020/5/8.
*/
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
private final int column;
private final int space;
private final int top;
/**
* Created by on 2020/5/8.
* Description: https://www.jianshu.com/p/b23e43f461c0 减掉RecyclerView父布局两侧padding和item的宽度,然后平分,默认每个item右侧会填充剩余空间
* int space = (Utils.getDeviceWidthPixels(getContext()) - spanCount * Utils.dip2px(getContext(), 80) - 2 * Utils.dip2px(getContext(), 15)) / (spanCount * (spanCount - 1));
* @param
* @return
*/
public SpaceItemDecoration(int space, int column, int top) {
this.space = space;
this.column = column;
this.top = top;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
// 第一列左边贴边、后边列项依次移动一个space和前一项移动的距离之和
int mod = parent.getChildAdapterPosition(view) % column;
outRect.left = space * mod;
outRect.top = top;
}
}
结论:推荐使用SpaceItemDecoration,第一种在存在拖动排序时,item间距无法均分。