美文网首页自定义控件
不正确使用ItemDecoration+GridLayoutMa

不正确使用ItemDecoration+GridLayoutMa

作者: Lucky丶夏日 | 来源:发表于2019-05-06 13:57 被阅读31次

    前言

    在项目中,我们经常使用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会自动均分的

    <?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" />
    

    相关文章

      网友评论

        本文标题:不正确使用ItemDecoration+GridLayoutMa

        本文链接:https://www.haomeiwen.com/subject/tnmroqtx.html