不正确使用ItemDecoration+GridLayoutManger导致宽度不对

前言

在项目中,我们经常使用RecyclerView来实现宫格布局(比如上传多张照片),我们会使用GridLayoutManger这种布局管理器配合ItemDecoration来实现。

可是有时不正当的ItemDecoration的写法会导致布局出现问题,比如,我们在实现如下界面时:


设计稿

根据设计稿来看,这个九宫格一行有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必然会出现里面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 列数
     * @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会自动均分的



你可能感兴趣的:(不正确使用ItemDecoration+GridLayoutManger导致宽度不对)