自定義 ItemDecoration 這個問題你真的注意到了嗎

SOLID發表於2017-04-07

本文討論的是關於自定義ItemDecoration容易被忽略的問題,此文適合有過自定義ItemDecoration經驗的同學閱讀,還沒有學習過的可以先去看看相關文章再來看本文。

ItemDecoration 我相信只要使用過RecyclerView的同學肯定都比較熟悉了,我們在使用 RecyclerView 的時候一般都是用這個來畫分隔線的,不得不說十分的好用。但是在最近發現在使用自定義的ItemDecoration上遇到了一些細節上的問題,我這裡自定義了一個GridDividerItemDecoration ,用於網格佈局的分隔,大概效果如下圖所示:

自定義 ItemDecoration 這個問題你真的注意到了嗎

繪製的邏輯大概是這樣的:當 itemView 不是最後一列或者最後一行的時候就繪製右側和底部分隔線,如果是最後一列時則不繪製右側分隔線,如果是最後一行則不繪製底部分隔線。

程式碼大概是這樣的

這裡的分割線設定的寬度只有1dp,看起來似乎沒有什麼問題,但是如果把分隔線的寬度設定為20dp效果如下圖所示:

自定義 ItemDecoration 這個問題你真的注意到了嗎

會明顯的感覺到最後一列itemView的寬度會比前幾列寬一些,具體的數值就是我們設定的 dividerWidth (也就是分隔線的寬度),正常情況下我們在自定義的 ItemDocration 設定 ItemOffsets 不會影響 itemView 的的大小,然而這裡卻出現了這個問題(其實網上絕大部分流行的關於網格的ItemDocration都存在這個問題),什麼原因呢,看看下面兩段原始碼就會知道了

由於我們這裡討論的是垂直方向上的Grid,所以 mOrientation == VERTICA,從上面的程式碼可以看出當我們的itemView寬度不是精確數值的時候,然後測量出的寬度就為 Math.max(0, parentSize – padding)(這裡的 padding 就是 horizontalInsets = decorInsets.left + decorInsets.right + lp.leftMargin + lp.rightMargin),原來這裡在實際的寬度下還減去了ItemDecoration的左右偏移量,這也就解釋了上面的那個問題。有人會問我們可不可以把寬度設定為固定值呢?可以當然是可以的,但是又會出現其他問題,下來你可以去嘗試一下,這裡我就不再去細究了。

一般情況下當 mOrientation == VERTICA 的時候itemView的寬度是 match_parent的,當 mOrientation == HORIZONTAL的時候itemView的高度就是 match_parent的,這樣才能更好的去適配各種螢幕的手機。

這裡我們找到了問題的原因所在,應該怎樣去解決呢? 其實也很簡單,就是均勻的分配offset給每一個itemView。

下面我們來計算一下偏移量。

// 每一個itemView的總偏移量(left+right)
eachOffset =(spanCount-1)* dividerWidth / spanCount;

L0=0 , R0=eachOffset;
L1=dividerWidth-R0 , R1=eachOffset-L1;
L2=dividerWidth-R1 , R2=eachOffset-L2;

其中:
Ln:表示第n列itemView left 偏移量。
Rn:表示第n列itemView right 偏移量。

可能有些同學看到上面式子會有點凌亂,這裡我直接告訴你最後推算出的結論好了,Ln 是一個以 dividerWidth-eachOffset 為差值的一個等差數列,Rn就等於 eachWidth-Ln。所以我們最後對 getItemOffsets 做了改進,程式碼如下:

最後的效果圖如下:

自定義 ItemDecoration 這個問題你真的注意到了嗎

完美的解決了上面出現的問題,這都是些細節上的問題,如果不怎麼注意,還真的很難去注意到,以後如果遇到其他類似的問題也可以很容易的解決了。本文只是討論了在使用ItemDecoration其中的一個問題,並不算難,但是也很重要,所以大家在平時的開發中還是應該多多注意細節上的問題。

最後送上本文原始碼地址:

  1. GridDividerItemDecoration
  2. GridDividerItemDecorationBug

順便給大家推薦一個十分強大的開源自定義的ItemDecoration ,適用於 LinearLayoutManager作為佈局管理器的RecyclerView : RecyclerView-FlexibleDivider

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

自定義 ItemDecoration 這個問題你真的注意到了嗎 自定義 ItemDecoration 這個問題你真的注意到了嗎

相關文章