自定義RecyclerView分割線

現(xiàn)在自己所寫的項目中用到列表的地方基本全部使用的是RecyclerView烤蜕,而使用列表就會有非常大的幾率用到分割線功能卖子。以前在用到RecyclerView的分割線功能的時候斩萌,都是利用RecyclerView自身設(shè)置的背景色和每個Item的背景色的差異玻褪,然后繼承RecyclerView.ItemDecoration许师,并且簡單的重寫
getItemOffsets (Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
方法就能達到效果了房蝉。簡單實現(xiàn)一個分割線效果代碼如下

  public void getItemOffsets (Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        switch (mOrientation) {
            case LinearLayoutManager.HORIZONTAL:
                outRect.right += mSpace;
                if (parent.getChildAdapterPosition (view) == 0)
                    outRect.left += mSpace;
                break;
            case LinearLayoutManager.VERTICAL:
                outRect.bottom += mSpace;
                if (parent.getChildAdapterPosition (view) == 0)
                    outRect.top += mSpace;
                break;
        }
    }

這樣就能實現(xiàn)最簡單的一個分割線的效果了∥⑶可是今天在寫項目的時候遇到了分割線顏色可能會變動的情況搭幻。因此上面這種簡單的方式就不能滿足要求了。

首先逞盆,Google了一番發(fā)現(xiàn)檀蹋,原來ItemDecoration能做的事遠遠不止這么簡單,它還能定制出更多的酷炫的效果云芦,不僅能在“Item下面”繪制分割線效果,還能在“Item上面”蓋章。要定制更多的效果就要重寫ItemDecoration的另外兩個方法
onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)

onDrawOver (Canvas c, RecyclerView parent, RecyclerView.State state)
onDraw方法要比Item 的onDraw方法先執(zhí)行盒件,所以它畫出的東西總是在Item的下面寸潦,在 onDraw 為 divider 設(shè)置繪制范圍,并繪制到 canvas 上琉历,而這個繪制范圍可以超出在 getItemOffsets 中設(shè)置的范圍坠七,但由于 decoration 是繪制在 childView 的底下水醋,所以并不可見,但是會存在overDraw灼捂。而onDrawOver 方法是在Item的onDraw執(zhí)行之后才執(zhí)行离例,所以onDrawOver畫出的東西是在Item的上面。仔細學(xué)習(xí)了一下onDrawOver方法悉稠,簡直像發(fā)現(xiàn)了新大陸一樣宫蛆。此次項目中,有個列表左邊需要展示一張圖片的猛,中間是4行文字描述耀盗,然后在右邊還是一張圖片,不過這張圖片要有蓋在文字上的效果類似于下面這樣

沒有原型卦尊,自己畫了個

我原本是用xml布局文件拼湊了這個效果叛拷。但是,仔細研究了onDrawOver方法后岂却,發(fā)現(xiàn)用onDrawOver也可以很好的實現(xiàn)此效果忿薇。xml文件代碼行數(shù)固然減少了很多而且加載效率肯定也有所提升,不過最重要的是感覺B格瞬間上升了很大一截

下面先放上自定義ItemDecoration的完整代碼

public class MyItemDecoration extends RecyclerView.ItemDecoration {
    private Drawable mDivider;
    private int mSize;
    private int mOrientation;
    private Paint mPaint;
    private Bitmap bitmap;

    public MyItemDecoration (Context context, int color, int drawableId, int size, int orientation) {
        mDivider = new ColorDrawable (color);
        mSize = size;
        mOrientation = orientation;
        bitmap = BitmapFactory.decodeResource (context.getResources (), drawableId);

        mPaint = new Paint ();
        mPaint.setColor (Color.RED);
        mPaint.setStyle (Paint.Style.FILL);
    }

    @Override
    public void getItemOffsets (Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
      switch (mOrientation){
            case  LinearLayoutManager.HORIZONTAL:
                outRect.right += mSize;
                break;
            case LinearLayoutManager.VERTICAL:
                outRect.bottom += mSize;
                break;
        }
    }


    @Override
    public void onDraw (Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left, right, top, bottom;
        if (mOrientation == LinearLayoutManager.VERTICAL) {
            left = parent.getPaddingLeft ();
            right = parent.getWidth () + parent.getPaddingRight ();
            int count = parent.getChildCount ();
            for (int i = 0; i < count; i++) {
                View child = parent.getChildAt (i);
                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams ();
                top = child.getBottom () + params.bottomMargin;
                bottom = top + mSize;
                mDivider.setBounds (left, top, right, bottom);
                mDivider.draw (c);
            }
        }
    }

    @Override
    public void onDrawOver (Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left, top;
        if (mOrientation == LinearLayoutManager.VERTICAL) {
            int childCount = parent.getChildCount ();
            for (int i = 0; i < childCount; i++) {
                View child = parent.getChildAt (i);
                left = child.getWidth () - bitmap.getWidth () - 15;
                top = child.getBottom () / 2 + (child.getBottom () / 2 * i) / (i + 1) - bitmap.getHeight () / 2;
                c.drawBitmap (bitmap, left, top, mPaint);
            }
        }
    }
}

下面是自己測試的實現(xiàn)效果



感覺很完美躏哩,右邊“異呈鸷疲”標(biāo)簽的位置也可以通過計算調(diào)整。

在自己摸索著寫這個MyItemDecoration 的過程中扫尺,遇到了個問題一并記錄一下筋栋。以前都是簡單的用,并沒有深入的了解過ItemDecoration正驻,也算給自己提個醒弊攘,以后不管學(xué)習(xí)還是工作,盡量多多的去延伸知識面
問題:只重寫onDraw方法也可以實現(xiàn)分割線的效果姑曙,那么getItemOffsets 的作用是又是什么呢襟交?
在遇到這個問題的時候,我覺得我占了一點好運氣渣磷,因為我給每個Item都設(shè)置了一個邊框婿着,如果沒有這個邊框,可能我會以為只重寫onDraw的效果就是正確的醋界,因為它“看起來”的效果確實是正確的竟宋。只重寫onDraw方法的時候出現(xiàn)的效果是這樣的

不重寫getItemOffsets方法.png

有分割線的效果,但是邊框卻“越過”了分割線和下一個Item相連了形纺,于是丘侠,我又重寫getItemOffsets方法,此時的效果就正常了逐样,如下
設(shè)置分割線.png

可是蜗字,為什么會出現(xiàn)“越過”分割線的效果呢打肝?經(jīng)過我自己多次對照代碼運行測試后發(fā)現(xiàn),畫第一個分割線的開始位置是這樣計算的

public void onDraw (Canvas c, RecyclerView parent, RecyclerView.State state) {
           ......
     for (int i = 0; i < childCount; i++) {
          View child = parent.getChildAt (i);
          top = child.getBottom () + params.bottomMargin;
          bottom = top + mSize;
           ......
        }

取得Item1.getBottom()作為第一條分割線的top挪捕,然后讓top加上設(shè)置的分割線的高度mSize作為第一條分割線的bottom粗梭,余下的分割線以此類推,此時不重寫getItemOffsets的情況下级零,畫個草圖更加一目了然


我是草圖.png

雖然通過onDraw方法畫出了分割線的效果断医,但是由于沒有重寫getItemOffsets()方法,所以RecyclerView的每個Item還是按照原始的布局位置設(shè)置奏纪,從3個紅色箭頭也可以看出
圖片頂部到Item1 top的距離 > 圖片到Item(x) top的距離鉴嗤,(x=2,3,4...)
這樣從Item2開始每個Item的頂部都少了一截mSize大小的高度,這就也解釋了為什么會出現(xiàn)邊框“越過”分割線的原因

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末序调,一起剝皮案震驚了整個濱河市醉锅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌发绢,老刑警劉巖硬耍,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異边酒,居然都是意外死亡默垄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門甚纲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人朦前,你說我怎么就攤上這事介杆。” “怎么了韭寸?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵春哨,是天一觀的道長。 經(jīng)常有香客問我恩伺,道長赴背,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任晶渠,我火速辦了婚禮凰荚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘褒脯。我一直安慰自己便瑟,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布番川。 她就那樣靜靜地躺著到涂,像睡著了一般脊框。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上践啄,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天浇雹,我揣著相機與錄音,去河邊找鬼屿讽。 笑死昭灵,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的聂儒。 我是一名探鬼主播虎锚,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼衩婚!你這毒婦竟也來了窜护?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤非春,失蹤者是張志新(化名)和其女友劉穎柱徙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奇昙,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡护侮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了储耐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羊初。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖什湘,靈堂內(nèi)的尸體忽然破棺而出长赞,到底是詐尸還是另有隱情,我是刑警寧澤闽撤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布得哆,位于F島的核電站,受9級特大地震影響哟旗,放射性物質(zhì)發(fā)生泄漏贩据。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一闸餐、第九天 我趴在偏房一處隱蔽的房頂上張望饱亮。 院中可真熱鬧,春花似錦舍沙、人聲如沸近尚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽戈锻。三九已至歼跟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間格遭,已是汗流浹背哈街。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拒迅,地道東北人骚秦。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像璧微,于是被迫代替她去往敵國和親作箍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容