继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Android RecyclerView 的 网格布局 ItemDecoration

白板的微信
关注TA
已关注
手记 341
粉丝 70
获赞 385

最近在使用同事写的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);
        }

    }
}

如有问题 欢迎指正

原文链接:http://www.apkbus.com/blog-98050-68215.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP