前言
在項目中,我們經常使用RecyclerView來實現(xiàn)宮格布局(比如上傳多張照片),我們會使用GridLayoutManger這種布局管理器配合ItemDecoration來實現(xiàn)。
可是有時不正當?shù)腎temDecoration的寫法會導致布局出現(xiàn)問題,比如,我們在實現(xiàn)如下界面時:

設計稿
根據(jù)設計稿來看,這個九宮格一行有3張圖,每行最左邊和最右邊跟卡片的間距先不管,每行或每列每2張圖之間間距為12dp,圖片大小為87dp x 87dp。如果我們照“正?!彼悸愤@樣寫ItemDecoration,效果就會變成下圖這樣。
錯誤示例

錯誤效果
//僅給出關鍵代碼
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
//獲得recyclerView的布局,需要轉化
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
int position = layoutParams.getViewAdapterPosition();
//獲得view在adapter的位置
if (position % 3 == 0)
outRect.right = dp2px(6);
else if (position % 3 == 1)
{
outRect.left = dp2px(6);
outRect.right = dp2px(6);
}
else
outRect.left = dp2px(6);
if (position > 2)
outRect.top = dp2px(12);
}
解決方案
如上面的效果圖和代碼,可以看出設置間隔后,左右2張圖把中間圖片的寬度分割了,導致中間的圖片會顯得比較“消瘦”。其實乍一看以上代碼重寫的getItemOffsets沒什么問題,但是getItemOffsets方法中,每個item中outRect的left和right如果加起來不一樣大,配合GridLayoutManger必然會出現(xiàn)里面item的寬度不對的問題。
那么我們該怎么寫ItemDecoration呢,因為我們效果圖是只有中間的圖和兩邊的圖有相等的間距,所以我們可以依舊使用getItemOffsets方法,但是要對其left和right作出一定的補償,如下代碼。
/**
* 作者:HK
* 日期:2019/5/5
* 描述:宮格布局的間隔處理
*
* 橫向:中間有等距間隔(左右兩邊與屏幕邊沿的間隔另行處理);
* 縱向:第二行往下開始,有頂部的間隔(且每行間隔都相等)
*/
public class GridItemDecoration extends RecyclerView.ItemDecoration {
private Context mContext;
private int spanCount;
private int dividerWidth;
/**
* @param spanCount gridLayoutManager 列數(shù)
* @param dividerWidthDp 分割塊的寬/高,單位:dp(m值,已適配)
*/
public GridItemDecoration(Context context, int spanCount, int dividerWidthDp) {
this.mContext = context;
this.spanCount = spanCount;
this.dividerWidth = dp2px(dividerWidthDp);
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View child, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, child, parent, state);
int pos = parent.getChildAdapterPosition(child);
// 計算這個child 處于第幾列
int column = (pos) % spanCount;
outRect.left = (column * dividerWidth / spanCount);
outRect.right = dividerWidth - (column + 1) * dividerWidth / spanCount;
if (pos >= spanCount)
outRect.top = dividerWidth;
}
private int dp2px(int values) {
return mContext.getResources().getDimensionPixelSize(ResourcesUtils.getDimen(
"m" + values, mContext));
}
}
//附上使用方式
private void setAdapter(RecyclerView rv)
{
...
rv.addItemDecoration(new GridItemDecoration(mContext, 3, 12));
GridLayoutManager layout = new GridLayoutManager(mContext, 3);
rv.setLayoutManager(layout);
...
}
item的布局,注意寬度要使用match_parent,別寫死,GridLayoutManger會自動均分的
<?xml version="1.0" encoding="utf-8"?>
<com.beautyperi.view.RoundImageView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/iv_icon"
android:layout_width="match_parent"
android:layout_height="@dimen/m87"
android:scaleType="centerCrop"
app:roundHeight="@dimen/m4"
app:roundWidth="@dimen/m4" />