RecycleView自定義ItemDecoration,實現時間軸效果

ali18510953445發表於2017-09-21

最近進行知識點掃盲,關於RecycleView的進行整理,自定義ItemDecoration,實現時間軸效果,先上圖:

這裡寫圖片描述

此文參考了Carson_Ho的部落格:http://www.jianshu.com/p/9a796bb23a47,在此特別感謝,感覺怎麼寫都沒有大神寫的好,但是還要自己記錄一下,嘿嘿。
時間軸是通過自定義ItemDecoration實現的,接下來我們分析一下ItemDecoration其內部的方法,
一、getItemOffsets
作用:設定ItemView的內嵌的偏移長度
其實在ItemView外部包含一層矩形,該方法就是決定其left,top,right,bottom的長度,完整方法如下:

@Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        // 引數說明:
        // 1. outRect:全為 0 的 Rect(包括著Item)
        // 2. view:RecyclerView 中的 檢視Item
        // 3. parent:RecyclerView 本身
        // 4. state:狀態

        outRect.set(50, 0, 0,50);
        // 4個引數分別對應左(Left)、上(Top)、右(Right)、下(Bottom)
        // 上述語句代表:左&下偏移長度=50px,右 & 上 偏移長度 = 0
        //具體過程:在RecyclerView進行子View寬高測量時(measureChild()),
        // 會將getItemOffsets()裡設定的 outRect4個屬性值(Top、Bottom、Left、Right)通過insert值累加 ,並最終新增到子View的 Padding屬性中

    }

二、onDraw
作用:顧名思義,用來繪製的,類似view的ondraw()方法,此處注意的是當ItemDecoration的ondraw與child view有重疊的區域,最終會顯示child的檢視,因為ItemDecoration先繪製子的itemView後繪製,此現象稱為onDraw()的 OverDraw。此方法一般配合上面的getItemOffsets,先給預留出空間,然後在此空間進行繪製,完整方法如下:

    //引數說明
    // 1、c  畫布
    //2、parent Recycle本身
    //3、state 狀態
   //通過此方法我們可以繪製想要繪製的圖案、圖片等     
 @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
    }

三、onDrawOver
作用:與上面的onDraw方法類似,唯一不同的是當ItemDecoration的ondraw與child view有重疊的區域,最終會顯示ItemDecoration的ondrawOver繪製的檢視,完整方法如下:

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

四、思路分析
通過上面的幾個方法我們完全可以自定義任何分割線了,然後分析時光軸,如下(借鑑):
這裡寫圖片描述

1、首先設定便宜長度,預留空間,
2、繪製時光軸
3、繪製時間文字,下面分別實現

1、首先設定偏移長度,預留空間,如下

//首先通過getItemOffsets方法設定相應的偏移量
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        // 設定ItemView的左 & 上偏移長度分別為200 px & 50px,即此為onDraw()可繪製的區域
        outRect.set(itemView_leftinterval, itemView_topinterval, 0, 0);
    }

2、繪製時光軸及文字都在onDraw()內實現,如下:

// 重寫onDraw()
    // 作用:在間隔區域裡繪製時光軸線 & 時間文字
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        //獲取子view的數量
        int count  =parent.getChildCount();
        //迴圈遍歷,分別獲取它們的位置資訊,然後再繪製對應的分割線
        for (int i = 0; i <count ; i++) {
            // 獲取每個Item物件
            View child = parent.getChildAt(i);

            /**
             * 繪製圖示
             */
            //自定義設定圖示位置
            float centerx = child.getLeft() - itemView_leftinterval / 3;
            float centery = child.getTop() - itemView_topinterval + (itemView_topinterval + child.getHeight()) / 2;
            // 通過Canvas繪製角標
             c.drawBitmap(mIcon,centerx - circle_radius ,centery - circle_radius,mPaint);

            /**
             * 繪製上半軸線
             */
            // 上端點座標(x,y)
            float upLine_up_x = centerx+circle_radius;
            float upLine_up_y = child.getTop() - itemView_topinterval;

            // 下端點座標(x,y)
            float upLine_bottom_x = centerx+circle_radius;
            float upLine_bottom_y = centery - circle_radius;

            //繪製上半部軸線
            c.drawLine(upLine_up_x, upLine_up_y, upLine_bottom_x, upLine_bottom_y, mPaint);

            /**
             * 繪製下半軸線
             */
            // 上端點座標(x,y)
            float bottomLine_up_x = centerx+circle_radius;
            float bottom_up_y = centery + circle_radius;

            // 下端點座標(x,y)
            float bottomLine_bottom_x = centerx+circle_radius;
            float bottomLine_bottom_y = child.getBottom();

            //繪製下半部軸線
            c.drawLine(bottomLine_up_x, bottom_up_y, bottomLine_bottom_x, bottomLine_bottom_y, mPaint);

            /**
             * 繪製左邊時間文字
             */
            // 獲取每個Item的位置
            int index = parent.getChildAdapterPosition(child);
            // 設定文字起始座標
            float Text_x = child.getLeft() - itemView_leftinterval * 5 / 6;
            float Text_y = upLine_bottom_y;

            // 根據Item位置設定時間文字
            for (int j = 0; j <timedata.size() ; j++) {
                if (index==j){
                    c.drawText((String)timedata.get(j).get("time"), Text_x, Text_y, mPaint1);
                    c.drawText((String)timedata.get(j).get("year"), Text_x + 5, Text_y + 20, mPaint2);
                }
            }
        }
    }

4,、在Activity中的使用

// times時間軸右邊的時間資料,bitmap是中間的圖片
    ry_time.addItemDecoration(new TimezItemdecor(BitmapFactory.decodeResource(getResources(),R.mipmap.earnings),listItem));

5、最終效果:
這裡寫圖片描述

總結;當我們知道ItemDecoration內部的三個方法用途之後,我們完全可以自己定義出各種更炫的效果,在此特別感謝Carson_Ho大神 http://www.jianshu.com/p/9a796bb23a47,縝密的思維,清晰的流程圖,化繁為簡,持續學習中。感謝生活,感謝科技,感謝分享!
五、原始碼地址
http://download.csdn.net/download/ali18510953445/9988209

相關文章