深刻RecyclerView-爲何要使用ItemDecoration

Part 1:不要用view作分割線

1-kX-yg-0eZKxyfA6oxQsjkg.jpeg

首先,什麼是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

不要用view作分割線 —會影響性能

我曾看到一些開發者在爲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而建立了額外的佈局。

不要用view作分割線 —會帶來反作用

由於divider是view的一部分,因此在item 動畫期間,divider也會一塊兒跟着動畫。以下圖:

1-bADMI7LYWaJo-ZGiWk0HVw.gif

顯然divider不該該隨着item一塊兒作動畫。而是和item分開,像這樣纔是對的:

1-Jk50iGRPixKN6oe9onq75w.gif

不要用view作分割線— 缺少靈活性

若是divider是(item的)view的一部分,那麼你就沒法控制它。你惟一能控制的就是根據item的position改變divider的可見狀態。 而item decoration就靈活多了。

1-VdxwtT2NKyLm3PkAxNwLvQ.png

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();
}

  

不要用view作分割線—使用 ItemDecoration

寫一個本身的ItemDecoration其實很是簡單。你只須要建立一個繼承了ItemDecoration的類就能夠了。重寫 getItemOffsets() 和 onDraw() 方法。具體實現能夠參考 這個 示例。

而 25.0.0版本的支持庫中,咱們有一個新的類 「DividerItemDecoration」。這個類直接實現了divider。

DividerItemDecoration decoration = new DividerItemDecoration(getApplicationContext(), VERTICAL);
recyclerView.addItemDecoration(decoration);

  

提示

  1. 一個RecyclerView能夠添加多個ItemDecoration。發揮頭腦風暴的時候到了。

  2. 全部decoration都在item繪製以前繪製。若是你想讓decoration在view以後繪製,重寫onDrawOver() 而不是onDraw() 。

因此下次想爲RecyclerView添加分割線的時候,別使用在item佈局添加view這種方式了,使用ItemDecoration。

相關文章
相關標籤/搜索