不正確使用ItemDecoration+GridLayoutManger導致寬度不對

前言

在項目中,我們經常使用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" />
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容