您的位置:首页 > 其它

给Grid方式排列的RecyclerView添加间距

2017-05-31 22:17 513 查看

给Grid方式排列的RecyclerView添加间距

现在需要排列一些小卡片,每行4个,从上往下排。卡片之间水平竖直间距30px。
毫无疑问,用的RecyclerView加GridLayoutManager。RecyclerView功能强大好用,怎么就是没有自带divider功能呢。
查找了一些资料,发现都是通过RecyclerView.addItemDecoration(RecyclerView.ItemDecoration decor)这个方法实现的。
由于我只是需要实现一个间距,所以,我只需实现重载getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent)方法就可以了。
最初,我只是这么实现的:


@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
//不是第一个的格子都设一个左边和底部的间距
outRect.left = space;
outRect.bottom = space;
//由于每行都只有column个,所以第一个都是column的倍数,把左边距设为0
if (parent.getChildLayoutPosition(view) %column==0) {
outRect.left = 0;
}
}


也就是,除了第一列,每一列的item都margin_left=space。然后,我就发现了个问题,这样做,会导致第一列的item比右侧的item大。item的大小加上边距的总大小是相等的,这样视觉上就很难看。同理,如果除了最后一列,每一列的item都margin_right=space,则最右边的item会比左边的item大。

然后我就想到了,平分间距到每个item上,这样他们的实际大小就一样了,具体分到每个item多少边距,则可以计算出来。

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
/*
* 除了第一行,每一行的每个item,距离顶部的item距离值space
* 水平间距略复杂:对于grid方式垂直滚动的recyclerview,假设有4列
* 排列如下:
* ———————————————————————————————————————————
* |    1    | |   2   | |   3    | |   4    |
* |    5    | |   6   | |   7    | |   8    |
* -------------------------------------------
* 如果给不是第一列的设置左边距,第一列的会比其他item宽一个边距
* 如果给不是最后一列的设置有右边距,同理,最后一列比其他item宽一个边距
* 也就是说,边距也是item的一部分,所以,这种方法,会导致四个item 不一样宽
*
* 下面的方法,通过算法,让每一列的所有item平均分担边距
* 对于 column = n 的grid,假设两个item间距是M:水平方向的内边距为:(n-1)*M
* 平均到每一个item后,平均是:A=(n-1)*M/n
* 则有如下规律:
* 1、第一列item的左边距为零,所以右边距只能是A
* 2、相邻左itemL,和右itemR,的左右边距和等于一个间距M
* 类推:
*      L       R
*   0  0       A
*   1  M-A     A-(M-A)
*   2  2(M-A)  A-2(M-A)
*   3  3(M-A)  A-3(M-A)
*   ...
*   n  n(M-A)  A-n(M-A)
*   n<=column
*/
outRect.top = space;
int pos = parent.getChildLayoutPosition(view);
int total = parent.getChildCount();
if (isFirstRow(pos)) {
outRect.top = 0;
}
if (isLastRow(pos, total)) {
outRect.bottom = 5;
}
if (column != DEFAULT_COLUMN) {
float avg = (column - 1) * space * 1.0f / column;
outRect.left = (int) (pos%column * (space - avg));
outRect.right = (int) (avg - (pos%column * (space - avg)));
}
}

boolean isFirstRow(int pos) {
return pos < column;
}

boolean isLastRow(int pos, int total) {
return total - pos <= column;
}


注释写的很清楚了。

下面是完整代码:

import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
* Created by zwx on 17-4-7
* RecyclerView 以Grid方式垂直排列,每一项item都是一个小卡片(cardview)
* 用于在item之间产生间距
*/
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {

private static final int DEFAULT_COLUMN = Integer.MAX_VALUE;
private int space;
private int column;

public SpaceItemDecoration(int space) {
this(space, DEFAULT_COLUMN);
}

public SpaceItemDecoration(int space, int column) {
this.space = space;
this.column = column;
}

@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
/*
* 除了第一行,每一行的每个item,距离顶部的item距离值space
* 水平间距略复杂:对于grid方式垂直滚动的recyclerview,假设有4列
* 排列如下:
* ———————————————————————————————————————————
* |    1    | |   2   | |   3    | |   4    |
* |    5    | |   6   | |   7    | |   8    |
* -------------------------------------------
* 如果给不是第一列的设置左边距,第一列的会比其他item宽一个边距
* 如果给不是最后一列的设置有白牛局,同理,最后一列比其他item宽一个边距
* 也就是说,边距也是item的一部分,所以,这种方法,会导致四个item 不一样宽
*
* 下面的方法,通过算法,让每一列的所有item平均分担边距
* 对于 column = n 的grid,假设两个item间距是M:水平方向的内边距为:(n-1)*M
* 平均到每一个item后,平均是:A=(n-1)*M/n
* 则有如下规律:
* 1、第一列item的左边距为零,所以右边距只能是A
* 2、相邻左itemL,和右itemR,的左右边距和等于一个间距M
* 类推:
*      L       R
*   0  0       A
*   1  M-A     A-(M-A)
*   2  2(M-A)  A-2(M-A)
*   3  3(M-A)  A-3(M-A)
*   ...
*   n  n(M-A)  A-n(M-A)
*   n<=column
*/
outRect.top = space;
int pos = parent.getChildLayoutPosition(view);
int total = parent.getChildCount();
if (isFirstRow(pos)) {
outRect.top = 0;
}
if (isLastRow(pos, total)) {
outRect.bottom = 5;
}
if (column != DEFAULT_COLUMN) {
float avg = (column - 1) * space * 1.0f / column;
outRect.left = (int) (pos%column * (space - avg));
outRect.right = (int) (avg - (pos%column * (space - avg)));
}
}

boolean isFirstRow(int pos) {
return pos < column;
}

boolean isLastRow(int pos, int total) {
return total - pos <= column;
}

boolean isFirstColumn(int pos) {
return pos % column == 0;
}

boolean isSecondColumn(int pos) {
return isFirstColumn(pos - 1);
}

boolean isEndColumn(int pos) {
return isFirstColumn(pos + 1);
}

boolean isNearEndColumn(int pos) {
return isEndColumn(pos + 1);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息