最近在使用同事写的GridSpaceItemDecoratoin时发现不太好用,准备自己重新写一个,于是在网上找资源

在Google找了不少资料,并不如意,故写下此篇

以这位大神的文章为蓝本,地址如下

Android RecyclerView 使用完全解析 体验艺术般的控件

大家可以先看一下,ps:个人不太习惯把别人写的很好的东西重新写一篇,直接引用了

先声明,文章并无意冒犯这位大神,仅想分享一下自己的方案,望共勉

文章的竖向列表的divider是没有问题的,但是网格布局的divider使用,是有问题,让我们先看一下Item偏移代码

  @Override    public void getItemOffsets(Rect outRect, int itemPosition,            RecyclerView parent)    {        int spanCount = getSpanCount(parent);        int childCount = parent.getAdapter().getItemCount();        if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部        {            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);        } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边        {            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());        } else        {            outRect.set(0, 0, mDivider.getIntrinsicWidth(),                    mDivider.getIntrinsicHeight());        }    }

代码逻辑是:最后一行不做底部偏移,最后一列不做右边偏移,其它都做右边和底部偏移,由此,最后一列的Item的宽度会比其它列要大Divider的尺寸

误处分析
  • 一个spanCount列的列表,加上divider后,一行Item减少的宽度为 (divider.size*spanCount-1)
  • 而代码中把这一行所减少的宽度平摊在0 - (spanCount-2)位置的Item上,最后一列未做减少,故导致最后一列Item变大
解决方案逻辑
  • 一个spanCount列的列表,加上divider后,一行Item减少的宽度为 dividerSize*(spanCount-1)
  • 则每个Item需减少 dividerSize*(spanCount-1)/spanCount
  • 相邻Item间距必须 是 dividerSize
  • 第一列Item的左边和最后一列Item的右边偏移必须是0
  • 依以上3条得出左右偏移量公式
  • left = column * dividerSize / spanCount;
  • right = dividerSize - (column + 1) * dividerSize / spanCount;
  • ps: column 为Item在该行的位置

附上完整代码

package com.senba.used.support.view.customRecycleView;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.support.annotation.ColorRes;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.RecyclerView.ItemDecoration;import android.support.v7.widget.StaggeredGridLayoutManager;import android.view.View;/** * Created by Mark on 2017/6/2. */public class GridItemDecoration extends ItemDecoration {    Paint mVerPaint, mHorPaint;    Builder mBuilder;    public GridItemDecoration(Builder builder) {        init(builder);    }    void init(Builder builder) {        this.mBuilder = builder;        mVerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mVerPaint.setStyle(Paint.Style.FILL);        mVerPaint.setColor(builder.verColor);        mHorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mHorPaint.setStyle(Paint.Style.FILL);        mHorPaint.setColor(builder.horColor);    }    private void drawHorizontal(Canvas c, RecyclerView parent) {        int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            if (mBuilder.isExistHeadView && i == 0)                continue;            View child = parent.getChildAt(i);            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();            final int left = child.getLeft() - params.leftMargin;            final int right = child.getRight() + params.rightMargin                    + mBuilder.dividerVerSize;            final int top = child.getBottom() + params.bottomMargin;            final int bottom = top + mBuilder.dividerHorSize;            c.drawRect(left, top, right, bottom, mHorPaint);        }    }    private void drawVertical(Canvas c, RecyclerView parent) {        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            if (mBuilder.isExistHeadView && i == 0)                continue;            final View child = parent.getChildAt(i);            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int top = child.getTop() - params.topMargin;            final int bottom = child.getBottom() + params.bottomMargin;            final int left = child.getRight() + params.rightMargin;            final int right = left + mBuilder.dividerVerSize;            c.drawRect(left, top, right, bottom, mVerPaint);        }    }    private int getSpanCount(RecyclerView parent) {        // 列数        int spanCount = -1;        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();        if (layoutManager instanceof GridLayoutManager) {            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();        } else if (layoutManager instanceof StaggeredGridLayoutManager) {            spanCount = ((StaggeredGridLayoutManager) layoutManager)                    .getSpanCount();        }        return spanCount;    }    private boolean isLastRaw(RecyclerView parent, int pos, int spanCount,                              int childCount) {        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();        if (layoutManager instanceof GridLayoutManager) {            childCount = childCount - childCount % spanCount;            if (pos >= childCount)                return true;        } else if (layoutManager instanceof StaggeredGridLayoutManager) {            int orientation = ((StaggeredGridLayoutManager) layoutManager)                    .getOrientation();            // StaggeredGridLayoutManager 且纵向滚动            if (orientation == StaggeredGridLayoutManager.VERTICAL) {                childCount = childCount - childCount % spanCount;                if (pos >= childCount)                    return true;            } else            // StaggeredGridLayoutManager 且横向滚动            {                if ((pos + 1) % spanCount == 0) {                    return true;                }            }        }        return false;    }    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        super.onDraw(c, parent, state);        drawHorizontal(c, parent);        drawVertical(c, parent);    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        int spanCount = getSpanCount(parent);        int childCount = parent.getAdapter().getItemCount();        int itemPosition = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();        if (mBuilder.isExistHeadView)            itemPosition -= 1;        if (itemPosition < 0)            return;        int column = itemPosition % spanCount;        int bottom = 0;        int left = column * mBuilder.dividerVerSize / spanCount;        int right = mBuilder.dividerVerSize - (column + 1) * mBuilder.dividerVerSize / spanCount;        if (!(isLastRaw(parent, itemPosition, spanCount, childCount) && !mBuilder.isShowLastDivider))            bottom = mBuilder.dividerHorSize;        outRect.set(left, 0, right, bottom);        marginOffsets(outRect, spanCount, itemPosition);    }    private void marginOffsets(Rect outRect, int spanCount, int itemPosition) {        if (mBuilder.marginRight == 0 && mBuilder.marginLeft == 0)            return;        int itemShrink = (mBuilder.marginLeft + mBuilder.marginRight) / spanCount;        outRect.left += (mBuilder.marginLeft - (itemPosition % spanCount) * itemShrink);        outRect.right += ((itemPosition % spanCount) + 1) * itemShrink - mBuilder.marginLeft;    }    public static class Builder {        private Context c;        int horColor;        int verColor;        int dividerHorSize;        int dividerVerSize;        int marginLeft, marginRight;        boolean isShowLastDivider = false;        boolean isExistHeadView = false;        public Builder(Context c) {            this.c = c;        }        /**         * 设置divider的颜色         *         * @param color         * @return         */        public Builder color(@ColorRes int color) {            this.horColor = c.getResources().getColor(color);            this.verColor = c.getResources().getColor(color);            return this;        }        /**         * 单独设置横向divider的颜色         *         * @param horColor         * @return         */        public Builder horColor(@ColorRes int horColor) {            this.horColor = c.getResources().getColor(horColor);            return this;        }        /**         * 单独设置纵向divider的颜色         *         * @param verColor         * @return         */        public Builder verColor(@ColorRes int verColor) {            this.verColor = c.getResources().getColor(verColor);            return this;        }        /**         * 设置divider的宽度         *         * @param size         * @return         */        public Builder size(int size) {            this.dividerHorSize = size;            this.dividerVerSize = size;            return this;        }        /**         * 设置横向divider的宽度         *         * @param horSize         * @return         */        public Builder horSize(int horSize) {            this.dividerHorSize = horSize;            return this;        }        /**         * 设置纵向divider的宽度         *         * @param verSize         * @return         */        public Builder verSize(int verSize) {            this.dividerVerSize = verSize;            return this;        }        /**         * 设置剔除HeadView的RecyclerView左右两边的外间距         *         * @param marginLeft         * @param marginRight         * @return         */        public Builder margin(int marginLeft, int marginRight) {            this.marginLeft = marginLeft;            this.marginRight = marginRight;            return this;        }        /**         * 最后一行divider是否需要显示         *         * @param isShow         * @return         */        public Builder showLastDivider(boolean isShow) {            this.isShowLastDivider = isShow;            return this;        }        /**         * 是否包含HeadView         *         * @param isExistHead         * @return         */        public Builder isExistHead(boolean isExistHead) {            this.isExistHeadView = isExistHead;            return this;        }        public GridItemDecoration build() {            return new GridItemDecoration(this);        }    }}

如有问题 欢迎指正

更多相关文章

  1. 设置EditText软键盘
  2. android中借助高德地图sdk实现基本的定位
  3. Android(安卓)沉浸式状态栏原理
  4. 模拟用户点击,“去除”USB弹框
  5. Android的配置界面PreferenceActivity
  6. 【Android(安卓)开发】:UI控件之 ImageView 实现图片旋转和缩放功
  7. Android中设置字体大小出现的问题(操作位置:Settings->Display->
  8. [快速搞定]android 状态栏一体化 沉浸式状态栏
  9. Android(安卓)selector设置详解

随机推荐

  1. Android(安卓)Studio 报No resource foun
  2. android java开发 第一天 之熟悉eclipse
  3. 如何修改应用兼容Android(安卓)3.0系统
  4. android activity的生命周期,四种启动模
  5. 让TextView 自带滚动条
  6. 不可或缺 Windows Native (25) - C++: wi
  7. Android(安卓)核心分析 之八------Androi
  8. android 扫描SD卡与系统文件(转)
  9. Android(安卓)自定义View(手写签名)
  10. android搭建环境错误 daemon not running