前言

Android5.0推出了RecyclerView控件来取代旧的ListView、GridView等控件,这个控件的功能非常强大,最重要的是它的整体性能要高于老的ListView、GridView控件。在设计上也更加注重职责分离,比如ListView包含了布局和回收功能、分隔线、顶部底部装饰布局等各种功能,RecyclerView则采用了可插拔式设计,能够根据用户设置不同的布局策略、分隔样式展现不同的界面效果。除此之外,RecyclerView还自带ViewHolder优化功能,用户所有的界面操作都面向ViewHolder,避免老的Adapter需要用户自己手动添加ViewHolder功能。

线性布局

首先开始学习如何使最简单的线性布局,这种布局就是从上向下的竖向或者从左到右横向一次展示每个数据条目视图。在开始使用时直接在XML文件中定义RecyclerView布局,设置宽高都是MATCH_PARENT。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerViewxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:background="@color/colorAccent"android:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.design.RecyclerViewActivity"></android.support.v7.widget.RecyclerView>

在Activity中查找到RecyclerView控件,并且为它设置布局方式为LinearLayoutManager,布局的方向为竖向布局,这样就能实现ListView样式的展示。

recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
// 设置线性布局管理器
recyclerView.setLayoutManager(layoutManager);
// 增加分割线效果
recyclerView.addItemDecoration(new LineDecoration());
// 设置Adapter生成视图
recyclerView.setAdapter(new RecyclerAdapter(this));

最后设置的Adapter和普通的ListView设置的Adapter是不相同的,这个Adapter需要继承自RecyclerView.Adapter,这个类的实现代码如下:

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {private List<User> users = new ArrayList<User>() {{add(new User(R.drawable.beach, "刘备", "唯贤唯德,能服于人"));add(new User(R.drawable.bamboo, "诸葛亮", "淡泊以明志,宁静以致远"));add(new User(R.drawable.road, "关羽", "安能与老兵同列"));add(new User(R.drawable.flower, "赵云", "子龙一身是胆"));add(new User(R.drawable.lake, "曹操", "宁教我负天下人,不教天下人负我"));add(new User(R.drawable.rain, "司马懿", "老而不死是为贼"));add(new User(R.drawable.sea, "司马昭", "司马昭之心路人皆知"));add(new User(R.drawable.moon, "孙权", "生子当如孙仲谋"));add(new User(R.drawable.peach, "周瑜", "既生瑜何生亮"));add(new User(R.drawable.pool, "吕蒙", "士别三日当刮目相待"));}};private Context context;private LayoutInflater inflater;public RecyclerAdapter(Context context) {this.context = context;this.inflater = LayoutInflater.from(context);}// 根据viewType生成对应的ViewHolder对象,ViewHolder对象@Overridepublic RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View itemView = inflater.inflate(R.layout.user_item, parent, false);return new RecyclerViewHolder(itemView);}// 调用数据和视图绑定功能@Overridepublic void onBindViewHolder(RecyclerViewHolder holder, int position) {holder.bindView(users.get(position));}// 数据条数@Overridepublic int getItemCount() {return users.size();}
}

这个Adapter是最简单的实现方式,只有一种视图布局类型,最后就是ViewHolder的实现了,这个类也需要继承自RecyclerView.ViewHolder类,可以看到RecyclerView封装了ViewHolder模式。

public class RecyclerViewHolder extends RecyclerView.ViewHolder {private ImageView portrait;private TextView name;private TextView desc;public RecyclerViewHolder(View itemView) {super(itemView);name = (TextView) itemView.findViewById(R.id.name);desc = (TextView) itemView.findViewById(R.id.desc);portrait = (ImageView) itemView.findViewById(R.id.portrait);}public void bindView(User user) {name.setText(user.getName());desc.setText(user.getDesc());portrait.setImageResource(user.getPortrait());}
}

代码实现都很简单,现在可以运行一下看下实现效果。

上面的实现效果和ListView基本一致,但是看不出来条目之间的分隔位置,这个只需要添加一个ItemDecoration对象就可以了,改对象有三个需要用户实现的接口方法,这里给出LinearItemDecoration的实现代码。

public class LineDecoration extends RecyclerView.ItemDecoration {private static final String TAG = "LineDecoration";private Paint paint;// 初始化画笔控件public LineDecoration() {paint = new Paint();paint.setAntiAlias(true);paint.setDither(true);paint.setStyle(Paint.Style.FILL);paint.setColor(Color.BLUE);}// 画出的内容在条目下方@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {Log.d(TAG, "onDraw()");int count = parent.getChildCount();for (int i = 0; i < count; i++) {View view = parent.getChildAt(i);int bottom = view.getBottom();c.drawRect(parent.getPaddingLeft(), bottom - CommonUtils.dp2px(25),parent.getWidth() - parent.getPaddingRight(), bottom + CommonUtils.dp2px(5), paint);}}// 画出来的内容在条目上方@Overridepublic void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
//        Log.d(TAG, "onDrawOver()");
//        int count = parent.getChildCount();
//        for (int i = 0; i < count; i++) {
//            View view = parent.getChildAt(i);
//            int bottom = view.getBottom();
//            c.drawRect(parent.getPaddingLeft(), bottom - CommonUtils.dp2px(25),
//                    parent.getWidth() - parent.getPaddingRight(), bottom + CommonUtils.dp2px(5), paint);
//        }}// 为展示条目设置额外的空间@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {Log.d(TAG, "getItemOffsets()");outRect.bottom = CommonUtils.dp2px(5);}
}

getItemOffsets方法就是为了每个条目设置额外的空间,用户可以在这些空间里绘制元素。如图所示outRect的各个属性对应着各个空间位置。

最后两张图分别对应着onDraw和onDrawOver的不同之处,用户可以清晰的看出它们之间的区别。

网格布局

网格布局采用了和GridView一样的布局方式,需要为RecyclerView设置网格布局管理器,定义网格布局的每行有三个元素。同时为了能够看到将数据分到不同的组中,这里采用了多布局样式功能。网格布局的Adapter对象定义如下:

public class GridRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {public static List<User> users = new ArrayList<User>() {{add(new User("蜀国"));add(new User(R.drawable.beach, "刘备", "唯贤唯德,能服于人"));add(new User(R.drawable.bamboo, "诸葛亮", "淡泊以明志,宁静以致远"));add(new User(R.drawable.road, "关羽", "安能与老兵同列"));add(new User(R.drawable.flower, "赵云", "子龙一身是胆"));add(new User("魏国"));add(new User(R.drawable.lake, "曹操", "宁教我负天下人,不教天下人负我"));add(new User(R.drawable.rain, "司马懿", "老而不死是为贼"));add(new User(R.drawable.sea, "司马昭", "司马昭之心路人皆知"));add(new User("吴国"));add(new User(R.drawable.moon, "孙权", "生子当如孙仲谋"));add(new User(R.drawable.peach, "周瑜", "既生瑜何生亮"));add(new User(R.drawable.pool, "吕蒙", "士别三日当刮目相待"));}};private Context context;private LayoutInflater inflater;public GridRecyclerAdapter(Context context) {this.context = context;this.inflater = LayoutInflater.from(context);}// 根据不同的布局样式生成不同的布局ViewHolder@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {RecyclerView.ViewHolder viewHolder = null;if (viewType == R.layout.grid_user_item) {View itemView = inflater.inflate(R.layout.grid_user_item, parent, false);viewHolder = new RecyclerViewHolder(itemView);} else {View itemView = inflater.inflate(R.layout.state_item, parent, false);viewHolder = new StateViewHolder(itemView);}return viewHolder;}// 根据不同布局样式绑定布局与数据@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {if (getItemViewType(position) == R.layout.grid_user_item) {((RecyclerViewHolder) holder).bindView(users.get(position));} else {((StateViewHolder) holder).bindView(users.get(position));}}@Overridepublic int getItemCount() {return users.size();}// 使用布局资源来区分布局的类型@Overridepublic int getItemViewType(int position) {User user = users.get(position);if (user.isHuman()) {return R.layout.grid_user_item;} else {return R.layout.state_item;}}
}

RecyclerViewHolder的实现前面已经贴出来了,这里在贴出StateViewHolder:

public class StateViewHolder extends RecyclerView.ViewHolder {private TextView text;public StateViewHolder(View itemView) {super(itemView);this.text = (TextView) itemView.findViewById(R.id.text);}public void bindView(User user) {text.setText(user.getName());}
}

最后是单元格之间的分隔,单元格是二维对象,需要在右边和下边都有分隔,实现代码如下:

public class GridItemDecoration extends RecyclerView.ItemDecoration {@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {}@Overridepublic void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {}@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {outRect.right = CommonUtils.dp2px(1);outRect.bottom = CommonUtils.dp2px(3);}
}

最终的实现效果如下:

瀑布流布局

瀑布流布局需要定义好方向,还需要定义在这个方向上有几行(列),感觉特别像人写字,展示几行就是写几行字,定义好写几行之后在开始定义怎么写,如果是竖行需要从上向下写,如果是横行就需要从左向右写,每一行写完后再到第二行接着写,直到所有的文字都写完。

recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
StaggeredGridLayoutManager staggeredGridLayoutManager =new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
recyclerView.addItemDecoration(new GridItemDecoration());
recyclerView.setAdapter(new GridRecyclerAdapter(this));

设置瀑布流管理布局很简单,其他的都和GridLayoutManager一样,设置完成之后展示结果如下图:

查看全部实现代码请点击查看源码

总结

RecyclerView的功能非常强大,除了上面提到的能够支持多种布局样式,它还提供了视图局部刷新功能,复杂的装饰布局支持,这些高级的用法还有待进一步学习。

RecyclerView基本使用方式相关推荐

  1. 实现对手机联系人列表进行读写操作,并用RecyclerView收缩展开方式展现

    实现对手机联系人列表进行读写操作,并用RecyclerView收缩展开方式展现 在之前做的类微信界面上加了显示手机联系人,姓名,电话,邮箱三项信息的功能,同时可以添加联系人同步到手机联系人记录中,添加 ...

  2. Android: ListView 和 RecyclerView 对比(一)

    1.ListView 由于手机屏幕空间有限,能够一次性在屏幕上显示的内容并不多,当程序中有大量的数据需要展示的时候,就可以借助 ListView 来实现.ListView 允许用户通过手指上下滑动的方 ...

  3. 用RecyclerView打造一个轮播图

    通常Android的轮播图(俗名:Banner)都是用ViewPager实现的,但是我在实际项目运用中碰到了一些小问题,于是决定另寻思路,采用RecyclerView这个更优雅更强大的控件来实现轮播的 ...

  4. Android 第十八课 强大的滚动控件 RecyclerView

    步骤: 一.添加依赖库 compile'com.android.support:recyclerview-v7:26.1.0' 二.在activity_mian.xml中,添加RecyclerView ...

  5. 利用RecyclerView实现无限轮播广告条

    代码地址如下: http://www.demodashi.com/demo/14771.html 前言: 公司产品需要新增悬浮广告条的功能,要求是可以循环滚动,并且点击相应的浮条会跳转到相应的界面,在 ...

  6. RecyclerView安卓androidx.widget.RecyclerView

    导入RecyclerView implementation 'com.android.support:recyclerview-v7:28.0.0' 或者把常用的组件都导入了,包括了RecyclerV ...

  7. Android开发基础——RecyclerView

    RecyclerView是比LitView更为强大的控件,其优化了ListView的不足.Android官方也更推荐使用RecyclerView. 基本用法 RecyclerView属于新增控件,Go ...

  8. Day4 自定义控件/ListView/RecyclerView

    创建自定义控件 引入布局 在新增的title.xml中创建一个自定义的标题栏: <LinearLayout xmlns:android="http://schemas.android. ...

  9. Android学习--RecyclerView的使用

    RecyclerView可以说是一个增强版的ListView 使用他之前我们需要在项目的build.gradle中添加相应的依赖库才可以 dependencies {compile fileTree( ...

最新文章

  1. android studio 自动提示jni代码,如何将JNI(C/C++本机代码)添加到现有的Android Studio项目中...
  2. SQL面试题: 数据库中有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列 ,当B列大于C列时选择B列否则选择C列 ,...
  3. 上下两个x轴_点胶机:3轴,4轴,5轴,你懂了吗?
  4. 昆仑mcp文件是什么版本_昆仑健康保2.0升级版怎么样?有哪些优缺点?
  5. JavaWeb 入门篇(1)Maven创建Web项目 Idea配置tomcat
  6. Chrome不显示OPTIONS请求的解决方法2021版chrome90
  7. Python 数据结构之栈的实现
  8. Javascript之ES7详解
  9. pythondef元组参数传递_Python参数传递(传值传引用)
  10. C++编程语言中创建类的对象(类的初始化)的方法
  11. qemu前后端features协商过程分析(vhost_user后端)
  12. idea 2017 常用图标
  13. ldap 统一认证 java_LDAP统一用户认证
  14. BLE相关:低功耗蓝牙原理
  15. 普通用户sudo echo权限依旧写入不了文件
  16. Linux thermal governor之IPA分析
  17. 使用css修改input的文字提示语颜色
  18. c语言开发谷歌浏览器插件,用Chrome学编程
  19. html5 div 颜色代码,div 字体颜色
  20. jQuery 读书笔记之一

热门文章

  1. Financial Vocabulary
  2. 缩略图Thumbnails
  3. ps -ef|grep tomcat是啥意思呢?(☆)
  4. 三十七、The authenticity of host ‘slave1 (192.168.231.106)‘ can‘t be established.
  5. 高手复盘:我所接触到的那些马丁策略(中)
  6. PAT-A-1042 Shuffling Machine
  7. python附加篇setup打包篇
  8. c语言中宏定义的字符替换#define M(x,y,z) x*y+z
  9. KM算法讲解(含C++代码)
  10. 百囚徒问题(100 prisoners problem)最佳策略Python代码实现(带详细注释)