给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); } }
相关文章推荐
- 给RecyclerView添加头部和尾部最简单的实现方式
- RecyclerView+GridLayoutManager 间距
- (4.1.45.2)RecyclerView实现带header的GridView效果:添加viewType方式
- RecyclerView添加Header的正确方式
- 解决recyclerView添加footView时,GridLayoutManager,StaggeredGridLayoutManager占满一行
- RecyclerView+GridLayoutManager展示时,间距问题~!
- RecyclerView添加Header的正确方式
- RecyclerView添加Header的正确方式
- Android Recyclerview GridLayoutManager列间距 - Android Recyclerview GridLayoutManager column spacing
- RecyclerView添加Header的正确方式
- 问题排除:RecyclerView添加分割线后,每次下拉刷新 Item与分割线间都会增加间距。
- AndroidRecyclerviewGridLayoutManager列间距 - Android Recyclerview GridLayoutManager column spacing
- AndroidRecyclerviewGridLayoutManager列间距 - Android Recyclerview GridLayoutManager column spacing
- RecyclerView添加Header的正确方式
- Android(java)学习笔记147:textView 添加超链接(两种实现方式,,区别于WebView)
- RecyclerView 动画 (添加、删除动画 以及 加载item 时的动画)
- RecyclerView 添加头部和尾部布局
- RecyclerView高度随Item自适应 GridLayoutManager和LinearLayoutManager都适用
- android v7兼容包RecyclerView的使用(四)——点击事件的不同方式处理
- Android TextView 添加连接方式