Android RecyclerView区分视图类型的Divider的实现

我们都知道support库有一个DividerItemDecoration, 可以作为Item之间的分隔线(divider)。但它作用以后所有的item之间都会有这个分隔线,实际情况往往是:recyclerView中存在多种的视图类型(viewType), 我们只是需要在某一类型的视图后添加分隔线。

要实现这种分隔线效果并不是什么难事,既然是某一类型有这个分隔线,那在直接在这种视图的layout文件上增加如下一个bottomLine界面元素妥妥的:

<View
  android:layout_width="match_parent"
  android:layout_height="0.5dp"
  android:background="@color/colorGrayLight" />

但如果添加这样一个界面元素导致新增一层布局那感觉代价有点大。另外一种情况,如果当前这个视图由于某种原因存在padding,而期望的分隔线是穿透整个布局的,那添加bottomLine的做法也是行不通的;还有一种情况同一类型布局在一个页面有分隔线,在另一个页面没有分隔线;总之就是希望分隔线和视图内容无关。所以我们需要一种类似DividerItemDecoration的decoration,它能针对某些viewType起作用。

先要了解一下RecyclerView.ItemDecoration,它有2个重要的回调方法:onDrawOver和getItemOffsets。onDrawOver其实是一种应用多个item的方法,所以无论如何都需要一个遍历操作。需要理解的是getItemOffsets中outRect这个输出型参数,虽然是一个Rect类型,但并不表示任何范围,而只是一个item四周的间隔距离:

outRect参数各域的含义

我们思路已经很清楚了: 在getItemOffsets中判断当前view的类型(parent.getChildViewHolder(view)), 如果是我们需要的类型设置对应的bottom;在onDrawOver中我们遍历recyclerView的child,同样如果是我们需要的类型将分隔线画在对应位置上就行了;这个decoration可以针对任意一种或者几种类型设置不种的drawable,我们当前用SparseArray存储,key就是视图的viewType
private final SparseArrayCompat<Drawable> mDividers = new SparseArrayCompat<>(2);
同时我们可以设置这个item的高度,当Drawable为null时相当于一个透明的间隙,不为null时具有强制指定的高度。
同样我们还要考虑方向:layoutManager为横向和竖向的情况,无它,只是画的位置不同而已。

话不多说了,上代码:

import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;

public class ViewTypeDivider extends ItemHolderDivider {

  @Override
  protected int keyFrom(RecyclerView.ViewHolder holder) {
    return holder.getItemViewType();
  }

  public ViewTypeDivider put(int viewType, Drawable drawable) {
    putDrawable(viewType, drawable);
    return this;
  }

  public ViewTypeDivider put(int viewType, @Nullable Drawable drawable, int height) {
    putHeight(viewType, drawable, height);
    return this;
  }
}
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v4.util.SparseArrayCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

abstract class ItemHolderDivider extends RecyclerView.ItemDecoration {
  private final SparseArrayCompat<Drawable> mDividers = new SparseArrayCompat<>(2);
  private final SparseArrayCompat<Integer> mHeights = new SparseArrayCompat<>(2);

  protected abstract int keyFrom(RecyclerView.ViewHolder holder);

  @Override
  public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
    final int childCount = parent.getChildCount();
    final int width = parent.getWidth();
    final int height = parent.getHeight();
    for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
      final View view = parent.getChildAt(childViewIndex);
      RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
      int key = keyFrom(holder);
      if (isVertical(parent)) {
        drawBottom(c, key, (int) view.getY() + view.getHeight(), width);
        drawTop(c, -key, (int) view.getY(), width);
      } else {
        drawRight(c, key, (int) view.getX() + view.getWidth(), height);
        drawLeft(c, -key, (int) view.getX(), height);
      }
    }
  }

  @Override
  public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                RecyclerView.State state) {
    RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
    int key = keyFrom(holder);
    if (isVertical(parent)) {
      outRect.bottom = getHeight(key);
      outRect.top = getHeight(-key);
    } else {
      outRect.right = getHeight(key);
      outRect.left = getHeight(-key);
    }
  }

  private void drawBottom(Canvas c, int key, int y, int width) {
    Drawable d = mDividers.get(key);
    if (d != null) {
      d.setBounds(0, y, width, y + getHeight(key, d));
      d.draw(c);
    }
  }

  private void drawTop(Canvas c, int key, int y, int width) {
    Drawable d = mDividers.get(key);
    if (d != null) {
      d.setBounds(0, y - getHeight(key, d), width, y);
      d.draw(c);
    }
  }

  private void drawRight(Canvas c, int key, int x, int height) {
    Drawable d = mDividers.get(key);
    if (d != null) {
      d.setBounds(x, 0, x + getHeight(key, d), height);
      d.draw(c);
    }
  }

  private void drawLeft(Canvas c, int key, int x, int height) {
    Drawable d = mDividers.get(key);
    if (d != null) {
      d.setBounds(x - getHeight(key, d), 0, x, height);
      d.draw(c);
    }
  }

  final void putDrawable(int key, Drawable drawable) {
    mDividers.put(key, drawable);
  }

  final void putHeight(int key, @Nullable Drawable drawable, int height) {
    if (drawable != null) {
      mDividers.put(key, drawable);
    }
    mHeights.put(key, height);
  }

  private int getHeight(int key) {
    Drawable d = mDividers.get(key);
    return getHeight(key, d);
  }

  private int getHeight(int key, @Nullable Drawable d) {
    int index = mHeights.indexOfKey(key);
    return index < 0 ? d == null ? 0 : d.getIntrinsicHeight() : mHeights.valueAt(index);
  }

  private boolean isVertical(RecyclerView parent) {
    RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
    return !(layoutManager instanceof LinearLayoutManager) ||
        ((LinearLayoutManager) layoutManager).getOrientation() == LinearLayoutManager.VERTICAL;
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • Android中使用RecyclerView实现下拉刷新和上拉加载
  • Android中RecyclerView布局代替GridView实现类似支付宝的界面
  • Android中RecyclerView实现横向滑动代码
  • Android RecyclerView实现下拉刷新和上拉加载
  • Android中RecyclerView实现多级折叠列表效果(二)
  • Android RecyclerView网格布局(支持多种分割线)详解(2)
  • Android项目实战之仿网易新闻的页面(RecyclerView )
  • Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法
  • Android中RecyclerView嵌套滑动冲突解决的代码片段
  • Android使用RecyclerView实现水平滚动控件
(0)

相关推荐

  • Android中使用RecyclerView实现下拉刷新和上拉加载

    推荐阅读:使用RecyclerView添加Header和Footer的方法                       RecyclerView的使用之HelloWorld RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好.本文给大家介绍如何为RecyclerView添加下拉刷新和上拉加载,过去在ListView当中添加下拉刷新和上拉加载是非常方便的利用addHeaderView和addFooterVie

  • Android RecyclerView 上拉加载更多及下拉刷新功能的实现方法

    RecyclerView 已经出来很久了,但是在项目中之前都使用的是ListView,最近新的项目上了都大量的使用了RecycleView.尤其是瀑布流的下拉刷新,网上吧啦吧啦没有合适的自己总结了一哈. 先贴图上来看看: 使用RecyclerView实现上拉加载更多和下拉刷新的功能我自己有两种方式: 1.使用系统自带的Android.support.v4.widget.SwipeRefreshLayout这个控价来实现. 2.自定义的里面带有RecyleView的控件. 使用RecycleVie

  • Android中RecyclerView嵌套滑动冲突解决的代码片段

    在纵向RecyclerView嵌套横向RecyclerView时,如果纵向RecyclerView有下拉刷新功能,那么内部的横向RecyclerView的横向滑动体验会很差.(只有纯横向滑动时,才能滑动内部的横向RecyclerView,否则滑动事件就会影响到下拉刷新),添加拦截判断. public class MySwipeRefreshLayout extends SwipeRefreshLayout { private boolean mIsVpDragger; private final

  • Android RecyclerView实现下拉刷新和上拉加载

    RecyclerView已经出来很久了,许许多多的项目都开始从ListView转战RecyclerView,那么,上拉加载和下拉刷新是一件很有必要的事情. 在ListView上,我们可以通过自己添加addHeadView和addFootView去添加头布局和底部局实现自定义的上拉和下拉,或者使用一些第三方库来简单的集成,例如Android-pulltorefresh或者android-Ultra-Pull-to-Refresh,后者的自定义更强,但需要自己实现上拉加载. 而在下面我们将用两种方式

  • Android RecyclerView网格布局(支持多种分割线)详解(2)

    上篇Android RecyclerView 详解(1)-线性布局 记录了下RecyclerView的使用方法,并且讲述了线性布局列表的使用方法,在此基础上加上了万能分割线,支持颜色分割线和图片分割线,同时支持对分割线设置线宽. 这篇是总结一下网格布局的使用,同样也支持两种分割线和线宽的设置. 主要的相关类: 1. RecyclerView.Adapter 2. GridLayoutManager 网格布局管理器 3. RecycleView.ItemDecoration 分割线 下面就直接通过

  • Android中RecyclerView布局代替GridView实现类似支付宝的界面

    单纯使用GridView 通用的两种给GridView 添加分割线的方法:http://stackoverflow.com/questions/7132030/android-gridview-draw-dividers 给Gridview 添加分割线,也就是实现网格布局,不清楚谷歌为什么没有给Gridview 添加一个类似 ListView 的Divider 属性,因此就需要我们自己去添加分割线, 目前两种方法,第一种是 利用GridView 的  android:horizontalSpac

  • Android使用RecyclerView实现水平滚动控件

    前言 相信大家都知道Android滚动控件的实现方式有很多, 使用RecyclerView也比较简单. 做了一个简单的年龄滚动控件, 让我们来看看RecyclerView的使用方式, 主要有以下几点: (1) 对齐控件中心位置. (2) 计算滚动距离. (3) 高亮中心视图. (4) 实时显示中心数据. (5) 停止时自动对齐. (6) 滚动时, 设置按钮状态开关. 效果 1. 框架 主要关注RecyclerView部分逻辑. /** * 初始化年龄滑动条 */ private void ini

  • Android中RecyclerView实现多级折叠列表效果(二)

    前言 在本文开始之前请大家先看一下这篇文章:http://www.jb51.net/article/113510.htm 上面的这篇文章是之前写的,里面发现有很多不好用地方,也学到些新姿势,改动了许多地方.下面来看看详细的介绍: 要点: 1.可以通过后台控制Item的展示. 2.TreeRecyclerAdapter,可以展开,折叠.多级展示 3.adapter可以使用装饰者模式进行扩展.支持EmptyAdapter.可以添加headview和footview 4.item的样式可以编写文档,t

  • Android项目实战之仿网易新闻的页面(RecyclerView )

    本文实例实现一个仿网易新闻的页面,上面是轮播的图片,下面是 RecyclerView 显示新闻列表,具体内容如下 错误方法 <?xml version="1.0" encoding="utf-8"?> <LinearLayout ...> <ViewPager ... /> <android.support.v7.widget.RecyclerView .../> </LinearLayout> 这样布局

  • Android中RecyclerView实现横向滑动代码

    RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好.本文给大家介绍Android中RecyclerView实现横向滑动代码,一起看看吧. android.support.v7.widget.RecyclerView 功能:RecyclerView横向滑动 控件:<android.support.v7.widget.RecyclerView /> Java类:RecyclerView.GalleryAdap

随机推荐