RecyclerView是Android 5.0新特性——Material Design中的一个控件,它将ListView、GridView整合到一起,可以使用极少的代码在ListView、GridView和瀑布流等布局方式之间转换。RecyclerView整体使用的是插件式的方式,解耦度相比提高了不少,非常灵活。

  RecyclerView之所以叫RecyclerView,是因为它的特性:它不关心Item是否显示在正确的位置上;不关心Item间如何分隔;不关心增加与删除的动画效果,只关心如何回收和复用View。

RecyclerView可以实现的Item布局方式:

  • 类似ListView的样式(横、纵都可以实现)
  • 类似GridView的样式(横、纵都可以实现)
  • 瀑布流样式(交错布局)

RecyclerView中可能用到的类:

  • LayoutManager:用来管理RecyclerView中的Item的布局方式
  • ItemDecoration:用来绘制RecyclerView中Item之间的间隔
  • ItemAnimation:用来绘制RecyclerView中的各种动画
  • RecyclerView.ViewHolder:用来存放每个Item中的控件
  • RecyclerView.Adapter:RecyclerView的适配器类的父类

1、RecyclerView适配数据:

  RecyclerView适配数据的方法和ListView、GridView使用的BaseAdapter适配数据的方法不太相同,RecyclerView内部提供了一个ViewHolder用来盛放item中出现的控件,相当于BaseAdapter中我们自己定义的ViewHolder相同,从这可以看出,从RecyclerView开始,Android开始“逼”我们对Item进行回收和复用;RecyclerView内部还提供了一个Adapter,其中有三个抽象方法:

  • getItemCount():获取Item的个数
  • onCreateViewHolder():返回当前Item的ViewHolder
  • onBindViewHolder():向ViewHolder中适配数据

  说了这么多,下面贴一下RecyclerView的适配器类RecyclerAdaper中的代码:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private Context context;
private List<String> data;
private LayoutInflater inflater; public RecyclerAdapter(Context context, List<String> data, boolean isStagger, OnRecyclerViewItemOperationListener listener) {
this.context = context;
this.data = data;
this.inflater = LayoutInflater.from(context);
} @Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.recycleritem_item, parent, false);
return new MyViewHolder(view);
} @Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.tv.setText(data.get(position));
} @Override
public int getItemCount() {
return data.size();
} static class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv; public MyViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.item_tv);
}
}
}

2、展示模式:

  如果是ListView或者GridView,那么直接设置适配器就可以显示数据了,而RecyclerView不行,因为RecyclerView是可以在ListView和GridView,甚至瀑布流之间进行任意切换的,因此我们还需要设置它的布局模式,这里就用到了LayoutManager类。LayoutManager是一个抽象类,我们最常用的子类有两个:LinearLayoutManager(适合线性布局,用于实现ListView的效果)和StaggeredGridLayoutManager(适合格子布局,用于实现GridView或瀑布流的效果)。

  我们可以通过RecyclerView对象的setLayoutManager()方法设置它的展示模式:

rv.setLayoutManager(new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false));

3、分隔线:

  这里说的分隔线是RecyclerView的Item之间的分隔线,其实我们大可以不用“正儿八经”的给RecyclerView设置分隔线,因为我们可以使用Item的margin来设置间距,简介实现分隔线的效果。

  RecyclerView也给我们提供了一个分隔线的抽象类——ItemDecoration,可以帮助我们实现分隔线,但是Android没有给我们提供这个类的子类,因此,我们需要自己去写。GitHub上有很多大神发布了一些分隔线的类,这里贴出其中一个DividerItemDecoration类来:

public class DividerItemDecoration extends RecyclerView.ItemDecoration {
// 系统默认的分隔条的Drawable资源的ID
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; // 绘制Item间间隔的Drawable
private Drawable mDivider;
// 方向(水平、数值)
private int mOrientation; public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
// 获取系统提供的分隔条的Drawable对象
mDivider = a.getDrawable(0);
// 回收TypedArray所占用的控件
a.recycle();
setOrientation(orientation);
} public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
} @Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
} /**
* 如果设置为纵向列表的样式,则调用这个方法
*/
public void drawVertical(Canvas c, RecyclerView parent) {
// Item距离左边缘的距离
final int left = parent.getPaddingLeft();
// Item距离右边缘的距离
final int right = parent.getWidth() - parent.getPaddingRight();
// 获取Item的总数
final int childCount = parent.getChildCount();
// 开始绘制所有Item之间的分隔线
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
RecyclerView v = new RecyclerView(parent.getContext());
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
// Item距离上边缘的距离
final int top = child.getBottom() + params.bottomMargin;
// Item距离下边缘的距离
final int bottom = top + mDivider.getIntrinsicHeight();
// 分隔线可以看成是一个长方形,所以需要设置它的上下左右的位置
mDivider.setBounds(left, top, right, bottom);
// 开始绘制分隔线
mDivider.draw(c);
}
} public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
} @Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}

  这样,我们只需要调用下面这行代码,就可以为RecyclerView设置分隔线了:

        // 设置RecyclerView的分隔线
rv.addItemDecoration(new DividerItemDecoration(MainActivity.this, DividerItemDecoration.VERTICAL_LIST));

  现在,我们倒回来看一下这个DividerItemDecoration类,其中提到了android.R.attr.listDivider这个属性,这个类中调用的是当前主题中设置的listDivider属性的值,我们可以通过修改主题中的这个属性来达到自定义分隔线的目的。我们只需要自己设计一个分隔线布局,然后在res/styles.xml文件中的AppTheme中添加下面这行代码,就可以实现自定义分隔线了:

<item name="android:listDivider">@drawable/divider_gradient</item>

4、动画:

  现在很多APP中都用到了RecyclerView,其中不乏有一些非常炫酷的动画,例如:向下滑动的时候使用动画添加Item、添加Item时候的动画、删除Item时候的动画等。GitHub上也有很多这类动画,大家可以找自己喜欢的动画来设置。

  这里用的是系统给我们提供的一种动画——DefaultItemAnimator,我们直接调用下面这行代码,就为RecyclerView设置好了动画。

        // 设置RecyclerView的动画效果
rv.setItemAnimator(new DefaultItemAnimator());

  这个动画只有添加/删除Item的时候的动画,没有下滑加载Item时候的动画。

5、点击和长按事件:

  RecyclerView中没有给我们提供OnClickListener、OnLongClickListener这类接口,因此,我们需要自己写,方法就是使用接口回调。我们可以在Adapter中设置一个接口,里面有点击和长按两个抽象方法,然后在onBindViewHolder()方法中设置Item的View的点击和长按事件,分别回调这两个抽象方法,然后在外界为Adapter对象设置这个接口即可。具体的Adapter的代码如下:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private Context context;
private List<String> data;
private LayoutInflater inflater; private OnRecyclerViewItemOperationListener listener; public RecyclerAdapter(Context context, List<String> data, boolean isStagger, OnRecyclerViewItemOperationListener listener) {
this.context = context;
this.data = data;
this.inflater = LayoutInflater.from(context);
this.listener = listener;
} @Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.recycleritem_item, parent, false);
return new MyViewHolder(view);
} @Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 如果不使用这个方法,则获取添加/删除的Item的position会出错
int layoutPosition = holder.getLayoutPosition();
listener.onRecyclerViewItemClickListener(layoutPosition);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
listener.onRecyclerViewItemLongClickListener(holder.getLayoutPosition());
return true;
}
});
holder.tv.setText(data.get(position));
} @Override
public int getItemCount() {
return data.size();
} static class MyViewHolder extends RecyclerView.ViewHolder {
TextView tv; public MyViewHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(R.id.item_tv);
}
} public interface OnRecyclerViewItemOperationListener {
void onRecyclerViewItemClickListener(int position); void onRecyclerViewItemLongClickListener(int position);
}
}

6、添加/删除Item:

  添加、删除操作主要就是修改适配器绑定的数据源中的数据,加一项或删一项。在RecyclerView中需要注意的是,如果我们为RecyclerView设置了动画,就不能调用Adapter对象的notifyDataSetChanged()方法去更新数据源,因为如果调用notifyDataSetChanged()方法,就没有了动画效果。我们需要调用notifyItemInserted()方法来更新添加Item后的数据源,调用notifyItemRemoved()方法来更新删除Item后的数据源。

  另外,在添加了新的Item之后,如果我们调用onBindViewHolder()方法参数中的position,就会出现新添加的Item的position不准确的问题,因此,我们需要使用holder.getLayoutPosition()方法来获取当前Item所在的位置。

  最后贴一下我做的一个RecyclerView的小DEMO中的截屏,然后贴源码地址:

      

      

  下面是码云上的源码地址,供大家参考。

DEMO地址

【Android - MD】之RecyclerView的使用的更多相关文章

  1. Android 高级编程 RecyclerView 控件的使用

    RecyclerView 是Android 新添加的一个用来取代ListView的控件,它的灵活性与可替代性比listview更好. 看一下继承关系: ava.lang.Object    ↳ and ...

  2. Android学习之RecyclerView

    RecyclerView是android-support-v7-21版本号中新增的一个Widget,官方介绍RecyclerView 是 ListView 的升级版本号,更加先进和灵活. 开发环境 - ...

  3. android开发学习 ------- RecyclerView多类型实例

    实现RecyclerView多类型的实例:效果如下图所示 public class CarFragment extends Fragment{ private View view; private R ...

  4. Android最新组件RecyclerView,替代ListView

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/40379159 万众瞩目的android最新5.0版本号不久前已经正式公布了,对于我 ...

  5. Android控件RecyclerView的基本用法

    Android控件RecyclerView的基本用法 转 https://www.jianshu.com/p/e71a4b73098f   github: https://github.com/Cym ...

  6. Android教程2020 - RecyclerView使用入门

    本文介绍RecyclerView的使用入门.这里给出一种比较常见的使用方式. Android教程2020 - 系列总览 本文链接 想必读者朋友对列表的表现形式已经不再陌生.手机上有联系人列表,文件列表 ...

  7. Android学习之RecyclerView初探究

    •RecyclerView基本用法 RecyclerView是新增的控件,为了让 RecyclerView 在所有 Android 版本上都能使用; Android 团队将 RecyclerView ...

  8. Android Studio开发RecyclerView遇到的各种问题以及解决(一)

    以前一直在用ListView,,,最近才看RecyclerView发现好强大.RecyclerView前提是Android版本在5.0以上,本人以前用的是eclipse只支持到4.4.索性就安装一个A ...

  9. 【Android - MD】之CoordinatorLayout的使用

    CoordinatorLayout是Android 5.0新特性--Material Design中的一个布局控件,主要用来协调各个子视图之间的工作,也可以用来作为顶部布局.CoordinatorLa ...

随机推荐

  1. 要想重启后也生效LINUX防火墙配置

    新配置的一台服务器,安装的是CentOS6.3系统,在安装完LNMP之后,发现nginx进程存在,且php解析正常,但是用分配的独立IP去访问的时候发现无法访问. 查了下网上的资料,发现可能是Linu ...

  2. chromium安装flash

    sudo apt-get install pepperflashplugin-nonfree sudo update-pepperflashplugin-nonfree --install Flash ...

  3. C#程序中:如何删除xml文件中的节点、元素。

    C#中动态的清理xml文件中的垃圾信息是程序员必会的哦.这就像数据库一样,不会清理数据怎么可以呢?其实xml文件就可以用作一个小的数据库,存储一些简单的信息.所以,用C#程序实现xml文件的增.删.改 ...

  4. ie9以上浏览器input文本框/密码框后面的小叉子/小眼睛问题

    找了很久不知什么属性控制的这个东西,经过群友的指点重要找到.

  5. 11-18的学习总结(DOMSecondday)

    DOM:读取访问节点对象属性 批量删除父元素下所有子节点 elem.innerHTML=""; 批量替换父元素下所有子节点 elem.innerHTML="所有子元素标签 ...

  6. 我的接口框架---框架函数文件common.php

    <?php defined('JDHU') OR die('no allow access'); /** * 加载配置文件 */ function &get_config($replac ...

  7. 批处理协同blat自动发邮件

    Blat - A Windows (32 & 64 bit) command line SMTP mailer. Use it to automatically eMail logs, the ...

  8. Login过滤器

    继承自ActionFilterAttibute public override void OnActionExecuting(ActionExecutingContext filterContext) ...

  9. unity Character Controller 点滴

    unity Character Controller  点滴 1.今天在做角色的时候,发现人物跳不起来,原来设置这个属性即可,Step Offset, 这个是台阶的高度,这个值设置的越大,人物爬的越高 ...

  10. ASP.NET 中Request.QueryString 中的key

    在ASP.net中 的Key是可能为null的,例如在如下的Url中 http://localhost:14546/Home/Index?a 有一个key=null 其value是a,以前一直以为ke ...