ScatteredLayoutManager,錯落排列的RecyclerView布局

效果如下圖所示:
Screenshot_2018-08-13-11-57-45.png

LayoutManager已經(jīng)有很多博客分享過自定義的方法和注意事項(xiàng),目前我也在學(xué)習(xí),不班門弄斧講原理。這個效果是在一個app上看到的,直接上實(shí)現(xiàn)代碼,有需要的可以參考一下。

public class ScatteredLayoutManager extends RecyclerView.LayoutManager {

    private int verticalScrollOffset;
    private int offsetH = 0;
    private int leftMargin, rightMargin;

    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT);
    }

    @Override
    public boolean isAutoMeasureEnabled() {
        return true;
    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        super.onLayoutChildren(recycler, state);
        if (getItemCount() == 0) {
            detachAndScrapAttachedViews(recycler);
            return;
        }
        if (getChildCount() == 0 && state.isPreLayout()) {
            return;
        }
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
                recycler.getViewForPosition(0).getLayoutParams();
        leftMargin = params.leftMargin;
        rightMargin = params.rightMargin;
        //先把所有item從RecyclerView中detach
        detachAndScrapAttachedViews(recycler);
        layoutItem(recycler);
    }

    private void layoutItem(RecyclerView.Recycler recycler) {
        offsetH = getPaddingTop();

        int width = (Resources.getSystem().getDisplayMetrics().widthPixels
                - getRightDecorationWidth(recycler.getViewForPosition(0))
                - getLeftDecorationWidth(recycler.getViewForPosition(0))
                - leftMargin - rightMargin) / 3;
        int round = 0;
        for (int i = 0; i < getItemCount(); i++) {
            View view = recycler.getViewForPosition(i);
            addView(view); // 因?yàn)閐etach過所以重新添加
            measureChildWithMargins(view, 0, 0);
            int height = getDecoratedMeasuredHeight(view);

            Rect mTmpRect = new Rect();
            calculateItemDecorationsForChild(view, mTmpRect);
            switch (i - round) {
                case 0:
                    layoutDecoratedWithMargins(view, 0, offsetH, 2 * width, offsetH + height);
                    break;
                case 1:
                    layoutDecoratedWithMargins(view, 2 * width, offsetH,
                            3 * width, offsetH + height / 2);
                    break;
                case 2:
                    layoutDecoratedWithMargins(view, 2 * width, offsetH + height / 2,
                            3 * width, offsetH + height);
                    offsetH = offsetH + height;
                    break;
                case 3:
                    layoutDecoratedWithMargins(view, 0, offsetH,
                            width, offsetH + height / 2);
                    break;
                case 4:
                    layoutDecoratedWithMargins(view, 0, offsetH + height / 2,
                            width, offsetH + height);
                    break;
                case 5:
                    layoutDecoratedWithMargins(view, width, offsetH,
                            3 * width, offsetH + height);
                    offsetH = offsetH + height;
                    break;
                default:
                    layoutDecoratedWithMargins(view, 0, offsetH, 3 * width,
                            offsetH + height);
                    offsetH = offsetH + height;
                    break;
            }
            if (i + 1 - round == 6)
                round += 6;
        }
    }

    @Override
    public boolean canScrollVertically() {
        return true;
    }

    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        //列表向下滾動dy為正,列表向上滾動dy為負(fù),這點(diǎn)與Android坐標(biāo)系保持一致。
        //實(shí)際要滑動的距離
        int travel = dy;
        //如果滑動到最頂部
        if (verticalScrollOffset + dy < 0) {
            travel = -verticalScrollOffset;
        } else if (verticalScrollOffset + dy > offsetH - getVerticalSpace()) {//如果滑動到最底部
            travel = offsetH - getVerticalSpace() - verticalScrollOffset;
        }
        //將豎直方向的偏移量+travel
        verticalScrollOffset += travel;
        // 調(diào)用該方法通知view在y方向上移動指定距離
        offsetChildrenVertical(-travel);

        return travel;
    }

    private int getVerticalSpace() {
        //計算RecyclerView的可用高度,除去上下Padding值
        return getHeight() - getPaddingBottom() - getPaddingTop();
    }
}

說明:目前只是將item的布局實(shí)現(xiàn),并且讓列表滾動起來,還沒時間去寫復(fù)用的代碼和一些優(yōu)化,有時間會更新。

https://github.com/HarveyLee1228/ScatteredLayoutManager

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容