使用ItemDecoration打造懸停分組頭部以及加header和footer(支持自定義view)

使用ItemDecoration打造懸停分組頭部,網(wǎng)上很多,但是大部分頭部都是一些文字圖形啥的,不夠靈活,于是我在此基礎(chǔ)上使用了自定義view來顯示分組頭部和懸停view。

先上圖:
Feb-01-2018 14-52-23.gif

還有footer,視屏有限制,就不放上來了。

可以看到頁面上是一個(gè)recyclerView。可以分為以下這幾部分,recyclerview,header, group(分組頭部),以及懸停頭部。懸停分組的知識(shí)已經(jīng)很多人寫了,我就不贅述了。 我主要說說這些自定義view是怎么畫上去的。

來看代碼:

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (header != null) {
            final int childCount = parent.getChildCount();
            for (int i = 0; i < childCount; i++) {

                View child = parent.getChildAt(i);
                int position = parent.getChildAdapterPosition(child);

                if (position == 0) {
                    c.translate(0, child.getTop() - header.getMeasuredHeight() - params.topMargin);
                    header.draw(c);
                    c.translate(0, header.getMeasuredHeight() - child.getTop() + params.topMargin);
                }
            }
        }
    }

這是給recyclerview加頭部的代碼。其中header需要我們提前給他處理好計(jì)算代碼放在最后,這其中的關(guān)鍵代碼即 c.translate(0, child.getTop() - header.getMeasuredHeight() - params.topMargin);
設(shè)置繪制header的起點(diǎn)。繪制完后,把canvas還原,如不還原會(huì)導(dǎo)致recycler view本體繪制出問題(ondraw在recycler view之前繪制)。

  @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (group == null) {
            return;
        }

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(child);
            if (isGroupFirst(position)) {
                ((BaseGroupRecyclerView) parent).setGroupData(group, position);
                buildView(group);
                int top = child.getBottom() - child.getHeight() - group.getMeasuredHeight() - params.topMargin;
                c.translate(0, top);
                group.draw(c);
                c.translate(0, -top);
            }
        }
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDrawOver(c, parent, state);

        if (!isStickHeader) {
            return;
        }

        final int childCount = parent.getChildCount();
        int preGroupName;
        int currentGroupName = -1;
        for (int i = 0; i < childCount; i++) {

            View view = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(view);

            preGroupName = currentGroupName;
            currentGroupName = mList.get(position);
            if (currentGroupName == preGroupName) {
                continue;
            }

            int viewBottom = view.getBottom();
            int top = Math.max(group.getMeasuredHeight(), view.getTop());

            if (position + 1 < state.getItemCount()) {
                int nextGroupName = mList.get(position + 1);
                if (currentGroupName != nextGroupName && viewBottom + params.topMargin * 2 < top) {
                    top = viewBottom + params.topMargin * 2;
                }
            }

            ((BaseGroupRecyclerView) parent).setGroupData(group, position);
            buildView(group);
            int marginTop = top - group.getMeasuredHeight() - params.topMargin;
            c.translate(0, marginTop);
            group.draw(c);
            c.translate(0, -marginTop);
            break;
        }
    }

這段代碼就是繪制分組頭部(onDraw方法),在最上面懸停的頭部(onDrawOver方法)。

我們來讀一下這段代碼。先多group判空, 然后對(duì)屏幕上顯示的item循環(huán),看那個(gè)是這一分組的第一個(gè),isGroupFirst這個(gè)方法自己定義呀,
((BaseGroupRecyclerView) parent).setGroupData(group, position);
buildView(group);
這兩句是我用來根據(jù)位置信息改變group顯示的內(nèi)容,可以忽略。我是在自定義recycler view里面生成此用于分組的itemdecoration對(duì)象,所以我的recycler view里可以直接操作此group對(duì)象。

buildView這個(gè)是因?yàn)楦牧薵roup的內(nèi)容,重新測量一下group的寬高。

接下來 計(jì)算group的起點(diǎn),不熟悉的可以自己查查手機(jī)屏幕坐標(biāo)系。
然后group.draw,把group畫出來。再還原c的起點(diǎn)。

onDrawOver里的思想是當(dāng)某一個(gè)分組頭部到屏幕頂了, 就在recycler view上邊畫出此group,制造出懸浮的效果。具體邏輯就不看了。主要的關(guān)鍵就在canvas的位置的轉(zhuǎn)換。

寫在最后,一開始我是看了這篇文章做的自定義view:
http://blog.csdn.net/xyq046463/article/details/53009635?locationNum=3&fps=1

他就做了一個(gè)頭部,并且滑動(dòng)的時(shí)候,把頭部向上變換,我當(dāng)時(shí)并不知道可以通過c.translate來改變畫筆的起點(diǎn)位置來改變view顯示的位置,于是我就把view.buildDrawingCache()變成一張圖片,通過 :
dst.set(left, top, right, bottom);設(shè)置圖片的位置,
c.drawBitmap(bitmap, null, dst, null);畫圖片。
來調(diào)整view的位置,這種方法我leader說效率不好,view轉(zhuǎn)換成bitmap耗時(shí)。于是我繼續(xù)想辦法,突然想到那個(gè)只做頭部的老哥通過c.translate的方法來改變畫筆的位置,于是我就想到了通過這種方法來改變view的顯示方式。

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

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

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