android n等分 layout,RecyclerView GridLayoutManager 等分间距
RecyclerView 表格實(shí)現(xiàn)
RecyclerView 配合GridLayoutManager 可以實(shí)現(xiàn)類似表格的樣式,為了實(shí)現(xiàn)均分,adapter 的布局寬度改為匹配父元素,即 android:layout_width="match_parent" 。
RecyclerView rvPhotoAlbums = findViewById(R.id.rv_photoAlbums_content);
rvPhotoAlbums.setLayoutManager(new GridLayoutManager(this, 4));
rvPhotoAlbums.setAdapter(new PhotoAlbumsAdapter());
復(fù)制代碼
效果圖如下:
添加間距 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 outRect 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的每個(gè)字段分別表示不同方向的偏移量,類似于填充或邊距。
* 默認(rèn)設(shè)置為0,即沒有間距。
*
*
* If this ItemDecoration does not affect the positioning of item views, it should set
* all four fields of outRect (left, top, right, bottom) to zero
* before returning.
* 如果不想影響item view 的位置,需要置outRect 的left, top, right, bottom 為0
*
*
* 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);
}
}
復(fù)制代碼
通過代碼注釋我們知道,可以通過繼承 androidx.recyclerview.widget.RecyclerView.ItemDecoration 類處理間距。
自定義ItemDecoration
public class GridSpaceItemDecoration extends RecyclerView.ItemDecoration{
private int mSpanCount;//橫條目數(shù)量
private int mRowSpacing;//行間距
private int mColumnSpacing;// 列間距
/**
* @param spanCount 列數(shù)
* @param rowSpacing 行間距
* @param columnSpacing 列間距
*/
public GridSpaceItemDecoration(int spanCount, int rowSpacing, int columnSpacing){
this.mSpanCount = spanCount;
this.mRowSpacing = rowSpacing;
this.mColumnSpacing = columnSpacing;
}
@Override
public 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 > 行數(shù),說明不是在第一行,則不指定行高,其他行的上間距為 top=mRowSpacing
if (position >= mSpanCount) {
outRect.top = mRowSpacing; // item top
}
}
}
復(fù)制代碼
添加ItemDecoration
// 添加間距
rvPhotoAlbums.addItemDecoration(new GridSpaceItemDecoration(4,
DpPxSpTool.INSTANCE.dip2px(this, 30),
DpPxSpTool.INSTANCE.dip2px(this, 20)));
復(fù)制代碼
ok,我們看下效果:
(注:為了區(qū)分item view范圍,我用不同的顏色描邊來識別)
可以看出,item 整體偏右,這是因?yàn)镚ridLayoutManager 已經(jīng)給item 劃分了寬度,而我們在ItemDecoration 中給item view設(shè)置了左邊距,所以會出現(xiàn)整體偏右,內(nèi)容擠壓的情況。
等分間距
實(shí)現(xiàn)思路
為了達(dá)到同等間距,我們需要同時(shí)設(shè)置item 的左右邊距,并且使 左邊view 的邊距+ 右邊view 的左邊距 = 設(shè)置的列間距,從視覺效果上看起來是同等分間距。
先來梳理下等間距需要滿足的條件:
各個(gè)模塊的大小相等,即各列的left+right 值相等;
各列的間距相等,即前列的right + 后列的left = 列間距;
假設(shè)列間距為10,為了方便識別,我用字母代替所在列。
以2列為例:
檢查條件1 :a.left +a.right = b.left+b.right = 5 結(jié)果:滿足
檢查條件2:a.right + b.left = 10 結(jié)果:滿足
以3列為例:
檢查條件1 :a.left +a.right = b.left+b.right = c.left+c.right ≈ 6.66 結(jié)果:滿足
檢查條件2:a.right + b.left = b.right + c.left ≈ 10 結(jié)果:滿足
根據(jù)推演我們可以得出公式:
某列的left = 所在的列數(shù) * (列間距 * (1 / 列數(shù)))
某列的right = 列間距 - 后列的left = 列間距 -(所在的列數(shù)+1) * (列間距 * (1 / 列數(shù)))
注:這里用的所在列數(shù)為從0開始
最終實(shí)現(xiàn)
/**
* 描述 : RecyclerView GridLayoutManager 等間距。
*
* 等間距需滿足兩個(gè)條件:
* 1.各個(gè)模塊的大小相等,即 各列的left+right 值相等;
* 2.各列的間距相等,即 前列的right + 后列的left = 列間距;
*
* 在{@link #getItemOffsets(Rect, View, RecyclerView, RecyclerView.State)} 中針對 outRect 的left 和right 滿足這兩個(gè)條件即可
*
* 作者 : shiguotao
* 版本 : V1
* 創(chuàng)建時(shí)間 : 2020/3/19 4:54 PM
*/
public class GridSpaceItemDecoration extends RecyclerView.ItemDecoration{
private final String TAG = "GridSpaceItemDecoration";
private int mSpanCount;//橫條目數(shù)量
private int mRowSpacing;//行間距
private int mColumnSpacing;// 列間距
/**
* @param spanCount 列數(shù)
* @param rowSpacing 行間距
* @param columnSpacing 列間距
*/
public GridSpaceItemDecoration(int spanCount, int rowSpacing, int columnSpacing){
this.mSpanCount = spanCount;
this.mRowSpacing = rowSpacing;
this.mColumnSpacing = columnSpacing;
}
@Override
public 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 / 列數(shù)))
outRect.right = mColumnSpacing - (column + 1) * mColumnSpacing / mSpanCount; // 列間距 - (column + 1) * (列間距 * (1f /列數(shù)))
Log.e(TAG, "position:" + position
+ " columnIndex: " + column
+ " left,right ->" + outRect.left + "," + outRect.right);
// 如果position > 行數(shù),說明不是在第一行,則不指定行高,其他行的上間距為 top=mRowSpacing
if (position >= mSpanCount) {
outRect.top = mRowSpacing; // item top
}
}
}
復(fù)制代碼
效果:
打完,收工!
總結(jié)
以上是生活随笔為你收集整理的android n等分 layout,RecyclerView GridLayoutManager 等分间距的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 开发常见问题,Andro
- 下一篇: HTML之CSS画三角形原理,纯CSS写