一个RecyclerView实现QQ空间相册布局

作者: Vincent7Wong | 来源:发表于2017-07-08 09:55 被阅读800次
    QQ空间相册效果图

    看到这布局自然会想到用RecyclerView来做,用ItemDecoration绘制日期那条分割线,每行3列的GridLayoutManager
    但是有个问题,如果不是正好3列、怎么去控制末尾的留白呢?

    我的实现思路是这样的:

    GridLayoutManager中有个setSpanSizeLookup方法,getSpanSize返回值就是控制每行有几列的

     gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    return setSpanSize(position, mAdapter.getDatas());
                }
            });
    

    不了解的可以转至RecyclerView通过GridLayoutManager实现多样式布局

    采用了setSpanSizeLookup方法

    也就是说使用该方法我可以控制每一行的列数、只要我再控制其长度就OK了

    在数据实体中添加一个value、用来记录当前图片和前面差了几个空白,从而确定留白的距离

     private int setSpanSize(int position, List<AlbumBean> listEntities) {
            int count;
            int d;
            if ((position + 1 < listEntities.size()) && position > 0) {
                if (!listEntities.get(position).getSubId().equals(listEntities.get(position + 1).getSubId())) {
                    mAdapter.getItem(position + 1).value = 2 - (mAdapter.getItem(position).value + position) % 3 
                                                           + mAdapter.getItem(position).value;
                    d = 2 - (mAdapter.getItem(position).value + position) % 3;
                    if (d == 2) {
                        count = 3;
                    } else if (d == 1) {
                        count = 2;
                    } else {
                        count = 1;
                    }
                } else {
                    mAdapter.getItem(position + 1).value = mAdapter.getItem(position).value;
                    count = 1;
                }
            } else if (position == 0) {
                if (mAdapter.getDatas().size() > 1) {
                    if ((!listEntities.get(position).getSubId().equals(listEntities.get(position + 1).getSubId()))) {
                        mAdapter.getItem(1).value = 2;
                        count = 3;
                    } else {
                        count = 1;
                        mAdapter.getItem(1).value = 0;
                    }
                } else {
                    count = 1;
                }
            } else {
                count = 1;
            }
            return count;
        }
    
    
    public class EaseItemDecoration extends RecyclerView.ItemDecoration {
        private final Drawable mDivider;
        private List<? extends AlbumBean> mDatas;
        private Paint mPaint;
        private Rect mBounds;
    
        private int mTitleHeight;
        private static int COLOR_TITLE_BG = Color.parseColor("#ffffff");
        private static int COLOR_TITLE_FONT = Color.parseColor("#333333");
        private static int mTitleFontSize;
    
        private int width;
    
        private static final int[] ATTRS = new int[]{
                android.R.attr.listDivider
        };
    
        public EaseItemDecoration(Context context, List<? extends AlbumBean> datas) {
            super();
            mDatas = datas;
            mPaint = new Paint();
            mBounds = new Rect();
            final TypedArray a = context.obtainStyledAttributes(ATTRS);
            mDivider = a.getDrawable(0);
            mTitleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 90, context.getResources().getDisplayMetrics());
            mTitleFontSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, context.getResources().getDisplayMetrics());
            mPaint.setTextSize(mTitleFontSize);
            mPaint.setAntiAlias(true);
            width = SmallUtil.getScreenWidth(context) / 3;
        }
    
        public void setmDatas(List<? extends AlbumBean> mDatas) {
            this.mDatas = mDatas;
        }
    
        @Override
        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
            super.onDraw(c, parent, state);
            final int left = parent.getPaddingLeft();
            final int right = parent.getWidth() - parent.getPaddingRight();
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = parent.getChildAt(i);
                final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                        .getLayoutParams();
                int position = params.getViewLayoutPosition();
                //我记得Rv的item position在重置时可能为-1.保险点判断一下吧
                if (position > -1) {
                    if (position == 0) {
                        drawTitleArea(c, left, right, child, params, position);
                    } else {
                        if (null != mDatas.get(position).getSubId() && !mDatas.get(position).getSubId().equals(mDatas.get(position - 1).getSubId())) {
                            //不为空 且跟前一个tag不一样了,说明是新的分类,也要title
                            drawTitleArea(c, left, right, child, params, position);
                        } else {
                        }
                    }
                }
            }
        }
    
        /**
         * 绘制Title区域背景和文字的方法
         */
        private void drawTitleArea(Canvas c, int left, int right, View child, RecyclerView.LayoutParams params, int position) {//最先调用,绘制在最下层
    
            mPaint.setColor(COLOR_TITLE_BG);
            c.drawRect(left, child.getTop() - params.topMargin - mTitleHeight, right, child.getTop() - params.topMargin, mPaint);
            mPaint.setColor(COLOR_TITLE_FONT);
            mPaint.setTextSize(SmallUtil.sp2px(17));
            String date = mDatas.get(position).getTitle();
            mPaint.getTextBounds(date, 0, date.length(), mBounds);
            c.drawText(date, (width * 3) / 2 - mBounds.width() / 2, child.getTop() - params.topMargin - mTitleHeight / 2, mPaint);
        }
    
        @Override
        public void onDrawOver(Canvas c, final RecyclerView parent, RecyclerView.State state) {//最后调用 绘制在最上层
        }
    
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            super.getItemOffsets(outRect, view, parent, state);
            int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
            if (position > -1 && position < mDatas.size()) {
                if (position + 1 < mDatas.size()) {
                    if (null != mDatas.get(position).getSubId() && !mDatas.get(position).getSubId().equals(mDatas.get(position + 1).getSubId())) {
                        int d = 2 - (mDatas.get(position).value + position) % 3;
                        if (isNewLine(position, mDatas)) {
                            outRect.set(0, mTitleHeight, width * d + mDivider.getIntrinsicHeight(), mDivider.getIntrinsicHeight());
                        } else {
                            outRect.set(0, 0, width * d + mDivider.getIntrinsicHeight(), mDivider.getIntrinsicHeight());
                        }
                    } else {
                        if (isNewLine(position, mDatas)) {
                            outRect.set(0, mTitleHeight, mDivider.getIntrinsicHeight(), mDivider.getIntrinsicHeight());
                        } else {
                            outRect.set(0, 0, mDivider.getIntrinsicHeight(), mDivider.getIntrinsicHeight());
                        }
                    }
                } else {
                    if (isNewLine(position, mDatas)) {
                        outRect.set(0, mTitleHeight, mDivider.getIntrinsicHeight(), mDivider.getIntrinsicHeight());
                    } else {
                        outRect.set(0, 0, mDivider.getIntrinsicHeight(), mDivider.getIntrinsicHeight());
                    }
                }
    
            }
        }
    
        private boolean isNewLine(int position, List<? extends AlbumBean> mDatas) {
            boolean isNew = false;
            if (position == 0 || position == 1 || position == 2)
                return true;
            int size = position > 2 ? position - 3 : 0;
            for (int i = size; i < position; i++) {
                if (null != mDatas.get(i).getSubId() && !mDatas.get(i).getSubId().equals(mDatas.get(i + 1).getSubId())) {
                    isNew = true;
                    break;
                }
            }
            return isNew;
        }
    }
    
    完成效果:
    完成效果图

    Github地址:https://github.com/forvv231/QQAlbum
    安装包下载:https://fir.im/QQAlbum

    相关文章

      网友评论

      本文标题:一个RecyclerView实现QQ空间相册布局

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