简介
概述
Android 5.0 新推出了RecyclerView组件,是ListView和GridView的替代方案。通过导入support-v7包进行使用,最低向前兼容到3.0。据官方的介绍,该控件用于在有限的窗口中展示大量数据集。
A flexible view for providing a limited window into a large data set.
优缺点
既然已经有了使用很久的ListView和GridView,为什么还要提出这个呢?
- 插拔式设计做到了高内聚低耦合。通过组合LayoutManager、ItemDecoration灵活实现各种效果。
- 标准化了ViewHolder。强制使用ViewHolder机制,简化了编写任务。
- 简单页面,不如ListView效率高。
- 添加头部首部较麻烦。
既然RecyclerView这么好,那就赶紧用起来吧?!向大家推荐一些教程,看完再继续也不迟。这些都是个人看过,认为入门较好的内容。强烈安利!相关连接在文末参考文献中前2个。
基本使用
实现列表布局
RecyclerView的使用主要有以下5步:
1,Activity初始化布局,绑定控件;
2,写item布局;
3,创建Adapter;
3.1 写ViewHolder内部类;
3.2 继承Adapter并添加泛型;
3.3 覆写Adapter方法;
4,布局管理器绑定;
5,绑定适配器。
Activity.class示例如下:
public class MainActivity extends AppCompatActivity {
//1. 初始化RecyclerView。
//2. 创建Item布局。例如:item_rvmain.xml布局。
RecyclerView mRecyclerView;
Class[] mClass = new Class[]{GridActivity.class, GridActivity.class, FallsActivity.class};
List<Class> mList;
RecyclerView.Adapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initDate();
mRecyclerView = findViewById(R.id.rv_main);
RecyclerView.LayoutManager manager = new LinearLayoutManager(this);
mAdapter = new MainAdapter(this, mList);
mRecyclerView.setLayoutManager(manager);
mRecyclerView.setAdapter(mAdapter);
}
private void initDate() {
mList = Arrays.asList(mClass);
}
}
MainAdapter.class示例如下:
//3. 创建Adapter。
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.MainHolder> {
//3.2 获取基本数据。
private Context mContext;
private List<Class> mDate;
protected MainAdapter(Context context, List<Class> date) {
mContext = context;
mDate = date;
}
//3.3 覆写相关方法。
@NonNull
@Override
public MainHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_rvmain, parent, false);
return new MainHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MainHolder holder, int position) {
final Class clazz = mDate.get(position);
holder.mTextView.setText(clazz.getSimpleName());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, clazz);
mContext.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mDate.size();
}
//3.1 创建ViewHolder。
class MainHolder extends RecyclerView.ViewHolder {
TextView mTextView;
public MainHolder(View itemView) {
super(itemView);
mTextView = itemView.findViewById(R.id.tv_main_item);
}
}
}
LayoutManager
Recyclerview在设计时,将Item的布局方式抽象出来,降低了View和布局管理器的耦合度,通过设置不同的管理器灵活的实现不同布局效果。
RecyclerView.LayoutManager的具体实现类有三个:线性布局管理器LinearLayoutManager
,网格布局管理器GridLayoutManager
,瀑布流布局管理器StaggeredGridLayoutManager
。
相信聪明的你已经想到了,当需要特殊布局时,只需要模拟这三个通过自定义LayoutManager,就可以随心所欲了。
GridLayoutManager
假如,你使用列表布局开发完了。突然XX产品来说:“列表的太普通了,改成网格的吧,突出我们的产品特色!”如果用的ListView相信你已经端起了显示器,但是!用了Recyclerview,我们就可以微笑的告诉XX:“幸亏老子聪明!”。
实现网格布局,只需要更改LayoutManager的类型就可以了。真的只改下面这一点代码:
RecyclerView.LayoutManager manager = new GridLayoutManager(this, 3);
具体代码参照示例中:GridActivity。
StaggeredGridLayoutManager
和网格布局一样潇洒!瀑布流布局也是so easy!只需要更改布局管理器,并在Adapter中动态设置Item的大小。
FallsStringAdapter.java
//1. 修改LayoutManager。
RecyclerView.LayoutManager manager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
//2. Adapter中动态设置大小。例如:
ViewGroup.LayoutParams params = holder.mTextView.getLayoutParams();
Random random = new Random();
params.height = random.nextInt(30) + 70;
params.width = params.width;
holder.mTextView.setLayoutParams(params);
具体代码参照示例中:FallsActivity。
ItemDecoration分割线
实现了三种常见效果后,相信你已经发现问题了,Item间怎么没有分割线?这也是设计时功能解耦导致的。官方将分割线的功能解耦到了RecyclerView.ItemDecoration
中,最开始官方只提供了此抽象类,由于需求很常见就把v7 samples中的DividerItemDecoration
添加到v7.widget包下。
DividerItemDecoration
使用DividerItemDecoration添加分割线也很简单,记得它支持LinearLayoutManager布局方式的布局:
RecyclerView.ItemDecoration divider = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(divider);
自定义ItemDecoration
当网格布局和瀑布流布局时,就需要通过自定义来实现了。首先来分析ItemDecoration
。主要有四个方法。当RecyclerView在绘制的时候,去会绘制decorator,即调用该类的onDraw和onDrawOver方法:
- onDraw()先于drawChildren
- onDrawOver()在drawChildren之后,这两个方法一般选择复写其中一个即可。
- getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator。
下面分析下,DividerItemDecoration的具体实现:
- 通过读取系统主题中的
android.R.attr.listDivider
作为Item间的分割线,值是个Drawable。 - 在
getItemOffsets()
中,outRect去设置了绘制的范围。 onDraw()
中实现了真正的绘制。
Theme方式自定义颜色
获取系统的android.R.attr.listDivider
的优点就是。我们可以通过设置系统主题灵活的变更分割线颜色。例如:
在styles.xml文件中,增加style:
<style name="DividerTheme" parent="AppTheme">
<item name="android:listDivider">@drawable/base_divider_bg</item>
</style>
在brawable中新建一个base_divider_bg.xml:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<gradient
android:centerColor="#ff00ff00"
android:endColor="#ff0000ff"
android:startColor="#ffff0000"
android:type="linear" />
<size android:height="4dp"/>
</shape>
在AndroidManifest.xml中,全局或者某个Activity中指定此样式即可:
<!-- 此是作用在整个应用中 -->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/DividerTheme">
...
<!-- 此是作用在DividerThemeActivity中 -->
<activity android:name=".divider.DividerThemeActivity"
android:theme="@style/DividerTheme"
></activity>
</application>
ColorDivider
色彩骚不骚?
网格类布局分割线
当网格布局或瀑布流布局时分割线怎么办呢?当然自定义了啊!
其他方法实现分割线
机制的小伙伴们也想出了其他一些骚操作来实现分割线效果。但都没有自定义Item完善,但也算是脑洞大开的想法吧。
Item中加控件
此种方法是,在Item布局中添加控件来实现效果,记得在Adapter中隐藏最后一个。
此方法看似简单,但增加了Item布局的复杂性,影响新能。不建议如此实现。
头部
不能像ListView快速添加头部。
资源
中阶
- BRVAH 闪电
BRVAH官方使用指南(持续更新)
搭配BRVAH高效使用RecyclerView - RecyclerView.ItemAnimator终极解读(三)–继承DefaultItemAnimator实现自定义动画
- RecyclerView使用神器:BRVAH使用简介
- Lrecycler中有一个DividerDecoration分割线类
- 仿房产销冠 APP 销控表界面-多 RecyclerView 同步滚动
- 真实项目运用-RecyclerView封装
- RecyclerView 源码分析
- RecyclerView使用完全指南,是时候体验新控件了(一)
错误
IllegalStateException: RecyclerView has no LayoutManager
此错误。发生原因:由于RecyclerView没有布局管理器,而在item的布局中触发了错误。
一般是:在RecyclerView中添加了View。
正确删除操作
BRVAH实践
优点
缺点
实际场景
- item的图片右上方有删除操作。其他方案:a,接口回调。在Adapter中添加监听接口。在逻辑中,回调接口。BRVAH:在Adapter中添加监听方法,在逻辑中为Adapter设置setOnItemChildClickListener();
参考文献
- RecyclerView 使用完全解析 体验艺术般的控件:鸿洋 鸿阳介绍,精简易懂。配合其视频更好
- 明日之星-RecyclerView 鸿阳视频。