深刻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。

相关文章
相关标签/搜索