本文主要是介绍RecyclerView GridLayoutManager 等分间距,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- RecyclerView 表格实现
- 添加间距 ItemDecoration
- ItemDecoration 源码分析
- 自定义ItemDecoration
- 添加ItemDecoration
- 等分间距
- 实现思路
- 最终实现
RecyclerView 表格实现
RecyclerView 配合GridLayoutManager 可以实现类似表格的样式,为了实现均分,adapter 的布局宽度改为匹配父元素,即 android:layout_width=“match_parent” 。
RecyclerView rvPhotoAlbums = findViewById(R.id.rv_photoAlbums_content);
rvPhotoAlbums.setLayoutManager(new GridLayoutManager(this, 4));
rvPhotoAlbums.setAdapter(new PhotoAlbumsAdapter());
效果图如下:
添加间距 ItemDecoration
ItemDecoration 源码分析
androidx.recyclerview.widget.RecyclerView#addItemDecoration(androidx.recyclerview.widget.RecyclerView.ItemDecoration)。
先简单看下 ItemDecoration 里的方法:
public abstract static class ItemDecoration {// ....省略其他方法介绍...../*** Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies* the number of pixels that the item view should be inset by, similar to padding or margin.* The default implementation sets the bounds of outRect to 0 and returns.* 解读:获取给定item view的偏移量,用outRect 表示。outRect的每个字段分别表示不同方向的偏移量,类似于填充或边距。* 默认设置为0,即没有间距。** <p>* If this ItemDecoration does not affect the positioning of item views, it should set* all four fields of <code>outRect</code> (left, top, right, bottom) to zero* before returning.* 如果不想影响item view 的位置,需要置outRect 的left, top, right, bottom 为0** <p>* If you need to access Adapter for additional data, you can call* {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the* View.** @param outRect Rect to receive the output.* @param view The child view to decorate* @param parent RecyclerView this ItemDecoration is decorating* @param state The current state of RecyclerView.*/public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,@NonNull RecyclerView parent, @NonNull State state) {getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),parent);}
}
通过代码注释我们知道,可以通过继承 androidx.recyclerview.widget.RecyclerView.ItemDecoration 类处理间距。
自定义ItemDecoration
public class GridSpaceItemDecoration extends RecyclerView.ItemDecoration {private int mSpanCount;//横条目数量private int mRowSpacing;//行间距private int mColumnSpacing;// 列间距/*** @param spanCount 列数* @param rowSpacing 行间距* @param columnSpacing 列间距*/public GridSpaceItemDecoration(int spanCount, int rowSpacing, int columnSpacing) {this.mSpanCount = spanCount;this.mRowSpacing = rowSpacing;this.mColumnSpacing = columnSpacing;}@Overridepublic void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {int position = parent.getChildAdapterPosition(view); // 获取view 在adapter中的位置。int column = position % mSpanCount; // view 所在的列// 列间距outRect.left = mColumnSpacing;// 如果position > 行数,说明不是在第一行,则不指定行高,其他行的上间距为 top=mRowSpacingif (position >= mSpanCount) {outRect.top = mRowSpacing; // item top}}
}
添加ItemDecoration
// 添加间距
rvPhotoAlbums.addItemDecoration(new GridSpaceItemDecoration(4,DpPxSpTool.INSTANCE.dip2px(this, 30),DpPxSpTool.INSTANCE.dip2px(this, 20)));
ok,我们看下效果:
(注:为了区分item view范围,我用不同的颜色描边来识别)
可以看出,item 整体偏右,这是因为GridLayoutManager 已经给item 划分了宽度,而我们在ItemDecoration 中给item view设置了左边距,所以会出现整体偏右,内容挤压的情况。
等分间距
实现思路
为了达到同等间距,我们需要同时设置item 的左右边距,并且使 左边view 的边距+ 右边view 的左边距 = 设置的列间距,从视觉效果上看起来是同等分间距。
先来梳理下等间距需要满足的条件:
- 各个模块的大小相等,即各列的left+right 值相等;
- 各列的间距相等,即前列的right + 后列的left = 列间距;
假设列间距为10,为了方便识别,我用字母代替所在列。
以2列为例:
检查条件1 :a.left +a.right = b.left+b.right = 5 结果:满足
检查条件2:a.right + b.left = 10 结果:满足
以3列为例:
检查条件1 :a.left +a.right = b.left+b.right = c.left+c.right ≈ 6.66 结果:满足
检查条件2:a.right + b.left = b.right + c.left ≈ 10 结果:满足
根据推演我们可以得出公式:
某列的left = 所在的列数 * (列间距 * (1 / 列数))
某列的right = 列间距 - 后列的left = 列间距 -(所在的列数+1) * (列间距 * (1 / 列数))
注:这里用的所在列数为从0开始
最终实现
/*** 描述 : RecyclerView GridLayoutManager 等间距。* <p>* 等间距需满足两个条件:* 1.各个模块的大小相等,即 各列的left+right 值相等;* 2.各列的间距相等,即 前列的right + 后列的left = 列间距;* <p>* 在{@link #getItemOffsets(Rect, View, RecyclerView, RecyclerView.State)} 中针对 outRect 的left 和right 满足这两个条件即可* <p>* 作者 : shiguotao* 版本 : V1* 创建时间 : 2020/3/19 4:54 PM*/
public class GridSpaceItemDecoration extends RecyclerView.ItemDecoration {private final String TAG = "GridSpaceItemDecoration";private int mSpanCount;//横条目数量private int mRowSpacing;//行间距private int mColumnSpacing;// 列间距/*** @param spanCount 列数* @param rowSpacing 行间距* @param columnSpacing 列间距*/public GridSpaceItemDecoration(int spanCount, int rowSpacing, int columnSpacing) {this.mSpanCount = spanCount;this.mRowSpacing = rowSpacing;this.mColumnSpacing = columnSpacing;}@Overridepublic void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {int position = parent.getChildAdapterPosition(view); // 获取view 在adapter中的位置。int column = position % mSpanCount; // view 所在的列outRect.left = column * mColumnSpacing / mSpanCount; // column * (列间距 * (1f / 列数))outRect.right = mColumnSpacing - (column + 1) * mColumnSpacing / mSpanCount; // 列间距 - (column + 1) * (列间距 * (1f /列数))Log.e(TAG, "position:" + position+ " columnIndex: " + column+ " left,right ->" + outRect.left + "," + outRect.right);// 如果position > 行数,说明不是在第一行,则不指定行高,其他行的上间距为 top=mRowSpacingif (position >= mSpanCount) {outRect.top = mRowSpacing; // item top}}
}
效果:
打完,收工!
这篇关于RecyclerView GridLayoutManager 等分间距的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!