首先,什麼是ItemDecoration?來看看官網是如何解釋的。html
ItemDecoration容許從adapter的數據集合中爲特定的item視圖添加特性的繪製以及佈局間隔。它能夠用來實現item之間的分割線,高亮,分組邊界等。
咱們不能簡單的把ItemDecoration當作一個名字響亮的分割線。它比divider要多不少內容。一個divider只能繪製在item之間,可是ItemDecoration能夠繪製在item的四邊。ItemDecoration爲decoration的測量和繪製提供了全方位的控制。一個decoration能夠是一條分割線,也能夠僅僅是一個間隔(inset)。java
但不幸的是,絕大多數android開發者都沒有使用item decoration。在這個分爲三部分的系列文章中,咱們將瞭解ItemDecoration的強大之處。android
第一部分: 不要添加view來作分割線— 使用 ItemDecorationcanvas
第二部分: 不要使用padding來作間隔 —使用 ItemDecorationide
第三部分: 在GridLayoutManager中高效的繪製decorations佈局
本文是第一部分。post
我曾看到一些開發者在爲RecyclerView添加divider的時候採用了一些捷徑。緣由很簡單,ListView原生支持divider,能夠直接在xml中設置divider。性能
<ListView android:id="@+id/activity_home_list_view" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="@android:color/black" android:dividerHeight="8dp"/>
可是到了RecyclerView,就不再能直接添加divider了。須要添加一個繪製divider的ItemDecoration。可是開發者發現它很麻煩,因而直接把divider添加到(item的)view上,而不是使用ItemDecoration。動畫
<LinearLayout android:orientation="vertical"> <LinearLayout android:orientation="horizontal"> <ImageView /> <TextView /> </LinearLayout> <View android:width="match_parent" android:height="1dp" android:background="#333" /> </LinearLayout>
每當咱們走捷徑的時候,都有可能會產生反作用。而這裏的反作用是可能影響性能。3d
當在佈局中添加了一個divider的時候,咱們增長了view的個數。咱們都知道view的數目越少會獲得越好的性能。有時候增長一個view來實現divider還會增長佈局的層級。好比上面的例子中,咱們不單單增長了一個view,還增長了一個包含它們的 linear layout。爲了一個divider而建立了額外的佈局。
由於divider是view的一部分,因此在item 動畫期間,divider也會一塊兒跟着動畫。以下圖:
顯然divider不該該隨着item一塊兒作動畫。而是和item分開,像這樣纔是對的:
若是divider是(item的)view的一部分,那麼你就沒法控制它。你惟一能控制的就是根據item的position改變divider的可見狀態。 而item decoration就靈活多了。
In the above image for the last item in the group divider fills the entire width. Other dividers have a margin of 56dp to their left side. Here is the ItemDecorator’s onDraw code.
在上圖中,group最後一個item的divider充滿了整個寬度。其它的divider都有一個56dp的左邊距。這是這個ItemDecorator的onDraw代碼:
@Override public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) { canvas.save(); final int leftWithMargin = convertDpToPixel(56); final int right = parent.getWidth(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); int adapterPosition = parent.getChildAdapterPosition(child); left = (adapterPosition == lastPosition) ? 0 : leftWithMargin; parent.getDecoratedBoundsWithMargins(child, mBounds); final int bottom = mBounds.bottom + Math.round(ViewCompat.getTranslationY(child)); final int top = bottom - mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(canvas); } canvas.restore(); }
寫一個本身的ItemDecoration其實很是簡單。你只須要建立一個繼承了ItemDecoration的類就能夠了。重寫 getItemOffsets() 和 onDraw() 方法。具體實現能夠參考 這個 示例。
而 25.0.0版本的支持庫中,咱們有一個新的類 「DividerItemDecoration」。這個類直接實現了divider。
DividerItemDecoration decoration = new DividerItemDecoration(getApplicationContext(), VERTICAL); recyclerView.addItemDecoration(decoration);
一個RecyclerView能夠添加多個ItemDecoration。發揮頭腦風暴的時候到了。
全部decoration都在item繪製以前繪製。若是你想讓decoration在view以後繪製,重寫onDrawOver() 而不是onDraw() 。
因此下次想爲RecyclerView添加分割線的時候,別使用在item佈局添加view這種方式了,使用ItemDecoration。