一個RecyclerView實現QQ空間相簿佈局

weixin_34129145發表於2017-07-08
5739496-16e3b543d82dfcb9.jpg
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實現多樣式佈局

5739496-f65b32a7d278f76d.png
採用了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;
    }
}
完成效果:
5739496-4204ddfdc01c1dd8.jpg
完成效果圖

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

相關文章