¶想法
RecyclerView 出来已经有好长时间了, 在自己的项目中却一直没有使用 … 这几天查阅了相关资料, 一步步地 check 着这个熟悉而又陌生的家伙, 自此爱不释手。
官方是这样介绍的:
RecyclerView is a more advanced and flexible version of ListView. This widget is a container for large sets of views that can be recycled and scrolled very efficiently. Use the RecyclerView widget when you have lists with elements that change dynamically.
写了一个 Demo, 包涵了如下功能, 下文也将依次以此展开 (适合新手, 大神绕道):
- RecyclerView 控件的基本用法 ;
- item 的 Click, LongClick 事件处理 ;
- 同一样式的 Item 不同布局的展示 ;
- Item 控件的状态变化处理, 如阅读痕迹等 …
写着写着, 大致有了如此模样:
**Demo 代码放在了这里:** https://github.com/absentm/Demo **Apk 下载地址:** https://github.com/absentm/Demo/blob/master/apk/RecyclerViewDemo.apk¶基本使用
¶添加包引用
在 Gradle 文件中添加 recyclerview 的包引用, cardview 也顺便加上吧:
1 | compile 'com.android.support:recyclerview-v7:24.+' |
¶XML 中定义
这个很基本了, 长这样就 ok :
1 | <android.support.v7.widget.RecyclerView |
¶Activity 中初始化
在 Activity 中需要查找 id , 初始化布局管理器(LayoutManager), 设置Adapter等, 大致如下:
1 | mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview); |
¶Adapter 构造适配器
到这里, 当和 ListView 做对比时, 可以发现 RecyclerView 似乎是在强制开发者使用 ListView 的 ViewHolder 模式, Adapter 的代码如下:
1 | import android.content.Context; |
¶数据源 mDatas
完成了以上操作, 还需要加载我们的数据。 Demo 的数据来自 ApiStore 的娱乐新闻 , 请求网络后返回 Json 格式数据。所以, 需要进行Json数据解析。
本文使用 Thread + Handler + Gson 技术进行网络数据加载和解析, 该技术的使用方法可参看我的这些文章:
Java中Gson的使用
Java中使用Gson解析json数据
Android 使用Thread+Handler实现非UI线程更新UI界面
数据加载和填充的核心代码如下:
1 | // 发送网络请求, 获取数据 |
¶Click 事件监听
以上基本上是 RecyclerView 的用法过程了, 但是 Google 却没有没给我们提供相应 Item 的点击事件处理, 我们需要自己改写自己的Adapter实现:
¶修改 Adapter
1 | // 使 Adapter implements View.OnClickListener, View.OnLongClickListener事件监听 |
注释较详细, 详见上文 Demo 的 Github 地址。
¶在 Activity 中处理 Item 点击事件的逻辑
1 | // 使 Activity 实现上述 Adapter 中定义的 Click 事件接口 |
这样点击事件的处理逻辑就 OK 了!
¶Item 状态变换处理
有时候, 我们还有这样的需求:
在列表中点击一个 Item 之后, 被点击的 Item 控件的字体颜色, 背景颜色或者图片是否显示等发生改变, 表现出和其他 Item 不一样的呈现状态。(如新闻点击阅读后, 当前新闻 Item 颜色变浅等)
我们的处理思路是: 在数据 Bean 中添加标记状态, 当 Item 的点击事件发生时改变当前数据 Bean 的标记状态, 之后使用 notifyDataSetChanged() 通知 Adapter 数据改变, 更新 UI 界面。因此, 需要如下代码处理。
¶数据 Bean 中添加标记属性
添加一个 isSelected 属性, 用于数据标记。
1 | import java.io.Serializable; |
¶Adapter 中根据 Bean 的标记状态设置不同显示效果
在 Adapter 中的 onBindViewHolder()方法中设置 Item 的不同加载状态。
1 | @Override |
¶Activtiy 的 Click() 方法中更改数据 Bean 标记状态
这样在相应的 Activity 中, 当点击事件发生时, 修改相关 Item 数据并通知 Adapter.
1 | @Override |
这样效果就出来了, 如展示图3所示。
¶样式切换
RecycleView 的布局管理器为我们提供了不同的布局样式, 如默认的线性列表布局, 网格布局, 瀑布流式布局等。Demo 中也提供了相关不同布局的切换, 如上图4, 5, 6所示。
思路是这样的: 在Adapter设置一个布局加载标志, 根据传回来的不同布局切换标志, 在 Adapter的 onCreateViewHolder() 方法中 inflate不同的布局, 具体做法如下:
¶Adapter 中添加加载布局标志
1 | public static int layoutFlag = 0; |
0: 默认卡片布局;
1: 无间隔卡片布局;
2: 瀑布流式布局;
3: 网格布局
¶改写 Adapter 中 onCreateViewHolder()方法
1 | @Override |
¶Activity 中 Menu 菜单触发布局切换事件
1 | // Menu 菜单 |
这样实现了基本效果, 但仍存在一个问题: Item 的标记状态存在内存中,随着 Activity 的消亡而消失; 可以考虑将数据 Bean 的标记状态存放在外部(数据库, SP, 网络等)
¶用到的开源库
特别感谢这些作者提供的开源库, 丰富了 Demo 功能。
compile ‘com.daimajia.numberprogressbar:library:1.2@aar’
compile ‘com.github.bumptech.glide:glide:3.7.0’
compile ‘com.google.code.gson:gson:2.8.0’
compile ‘com.afollestad.material-dialogs:commons:0.9.0.1’
compile ‘com.jaeger.statusbaruitl:library:1.3.0’
compile ‘de.hdodenhof:circleimageview:2.1.0’
¶参考资料
[1] http://blog.csdn.net/lmj623565791/article/details/45059587
[2] http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1118/2004.html
[3] http://www.loongwind.com/archives/189.html
[4] http://frank-zhu.github.io/android/2015/01/16/android-recyclerview-part-1/
[5] https://github.com/Tikitoo/blog/issues/29