下面结论都是基于GridLayoutManager方向为竖直,spanCount为列数的情况,但在水平方向类似。
SpanSizeLookup
public int getSpanIndex(int position, int spanCount)
返回值:position对应item所在列的起始indexpublic abstract int getSpanSize(int position)
返回值:position对应item所跨越列的数量(所占spanCount的份额)public int getSpanGroupIndex(int adapterPosition, int spanCount)
返回值:position对应item所属组的index, 如果是竖直方向就表示所在的行号
假设一个grid为5列,有一个item在第二行,宽度从第二列开始到最后一列。
那么那么这个item宽度占了4列,所以getSpanSize等于4。
在第二行,所以getSpanGroupIndex等于1。
宽度从第二列开始,所以getSpanIndex等于1。
ItemDecoration
在使用decoration做间距,getItemOffsets方法中使用Rect为每个item分配间距,如果每个item的左右间距之和不相等,则会导致最终每个item不是均分。
假设每个item之间的间隔为a,记每个item左间距为L0,L1,L2....Ln-1,右间距为R0,R1,R2....Rn-1,n为网格列表的列数。
常数k= ((n-1)*a)/n,每个item分配间距分配到的间距之和。
第一列: L0 = 0, R0= k
第二列:L1 =a-R0, R1 = k-L1
第三列:L2 = a-R1,R2=k-L2
......
第N个:L(n-1) = a - R(n-2), R(n-1) = k-L(n-1)
通过上面关系可以通过整理一个方法
private val cache = HashMap<Int, Pair<Int, Int>>()
/**
* 获取指定列的左右间距
* @param columnIndex列的索引
* @param itemSpace 每个item之间的间距
* @param k 平分到每个item的左右间距之和
* @return Pair.first表示左间距,Pair.second表示右间距
*/
private fun getHorizontalMargin(columnIndex: Int, itemSpace: Int, k: Int): Pair<Int, Int> {
if (columnIndex == 0) {
return 0 to k
}
var prev = cache[columnIndex - 1]
if (prev == null) {
prev = getHorizontalMargin(columnIndex - 1, itemSpace, k)
cache[columnIndex-1] = prev
}
val left = itemSpace - prev.second
val right = k - left
return left to right
}
其中
val k = (总列数 * space - space) / 总列数
val columnIndex = position % 总列数