本文目录
一、概述
RecyclerView 是在 Android5.0 之后,Google 推出的一个新控件,是作为 ListView、GridView 的替代者出现的。它具有比上述两者更高的灵活性,在功能上也更加强大。Google 官方对它的定义是:
A flexible view for providing a limited window into a large data set.
向一个有限的窗口(window)提供大量数据集的灵活视图(view)。
先来看看 RecyclerView 能实现哪些效果:
由于 RecylerView 定义在了 support 库中,如果我们想要使用 RecyclerView 控件,需要向项目中的 build.gradle添加代码 implementation ‘com.android.support:recyclerview-v7:27.1.1’ ,如下所示:
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:recyclerview-v7:27.1.1'
}
添加完之后一定要记得点一下右上角的 Sync Now 进行同步,否则可能会出现错误。
二、列表视图的处理
1. item 的布局文件
首先,在 activity_main 中添加 RecyclerView 控件,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
其次,在 layout 文件夹下新建一个 Layout Resource file,命名为 item_recycler_view,它是 RecyclerView 中 item(即子项)的布局文件,我们需要的 item 布局为图片(ImageView)和文字(TextView)的组合,所以代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_item"
android:layout_width="80dp"
android:layout_height="80dp" />
<TextView
android:id="@+id/tv_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="20dp"
android:textSize="15sp" />
</LinearLayout>
2. 构造 Adapter 类
既然展示的是关于食物的图片和文字的视图,那么我们就新建一个 Food 类来存取我们每个食物(Food)的实例,代码如下:
public class Food {
// 食物的图片id
private int imageId;
// 食物的名字
private String name;
// 构造函数
public Food(String name, int imageId){
this.imageId = imageId;
this.name = name;
}
// 获取食物的图片id
public int getImageId() {
return imageId;
}
// 获取食物的名字
public String getName() {
return name;
}
}
接着,为我们的 RecyclerView 定义一个 Adapter 类。和 ListView 一样,RecyclerView 也需要使用 Adapter 适配器,现在我们新建一个 MyAdapter 类,继承自 RecyclerView.Adapter,其中泛型参数 VH 表示的就是 ViewHolder ,这里我们将泛型类型指定为 MyAdapter.ViewHolder,它是 MyAdapter 中我们自己定义的一个 的内部类,继承自 Recycler.ViewHolder。
我们还需要在 MyAdapter 类中覆写三个方法 :onCreateViewHolder()、onBindViewHolder() 和 getItemCount(),新建好的代码如下:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
// 存储 Food 类型数据的数据源
private List<Food> mFoodList;
// 构造方法用于传入数据
public MyAdapter(List<Food> list){
mFoodList = list;
}
// 创建 ViewHolder的实例,在这里加载 item_recycler_view
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
return null;
}
// 绑定 ViewHolder,用于对每个 item 进行赋值操作
@Override
public void onBindViewHolder(ViewHolder holder, int position){
}
// 获取 item 的数量
@Override
public int getItemCount(){
return 0;
}
// 自定义的 ViewHolder 类,继承自 RecyclerView.ViewHolder
static class ViewHolder extends RecyclerView.ViewHolder{
View view;
ViewHolder(View view){
super(view);
this.view = view;
}
}
}
分析一下这段代码,mFoodList 是用于存储 Food 类型数据的数据源,它通过构造方法获取数据。接下来看第一个需要覆写的方法 onCreateViewHolder(),从字面上理解,顾名思义,就是需要我们在这个方法中创建 ViewHolder 实例。在这个方法中,我们将之前写好的布局文件 item_recycler_view 加载进来,并创建一个 ViewHolder 实例返回。代码如下:
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
// 传入子项(item)的布局文件
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_recycler_view, parent, false);
// 创建 ViewHolder 实例
ViewHolder holder = new ViewHolder(view);
return holder;
}
接下来是第二个覆写方法 onBindViewHolder(),该方法用于对 RecyclerView 子项的数据进行赋值,我们可以通过第二个参数 position 来获取当前项的 Food 实例,然后把 Food 实例中的数据传入 holder 的 ImageView 和 TextView 中。代码如下:
@Override
public void onBindViewHolder(ViewHolder holder, int position){
// 获取当前项的 Food 实例
Food food = mFoodList.get(position);
TextView textView = holder.view.findViewById(R.id.tv_item);
ImageView imageView = holder.view.findViewById(R.id.iv_item);
textView.setText(food.getName());
imageView.setImageResource(food.getImageId());
}
最后一个覆写方法 getItemCount() 就很简单了,因为是获取 item 的个数,所以直接返回 mFoodList 的长度即可。
@Override
public int getItemCount(){
return mFoodList.size();
}
完整的 MyAdapter 类代码如下所示:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
// 存储 Food 类型数据的数据源
private List<Food> mFoodList;
// 构造方法用于传入数据
public MyAdapter(List<Food> list){
mFoodList = list;
}
// 创建 ViewHolder的实例,在这里加载 item_recycler_view
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
// 传入子项(item)的布局文件
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_recycler_view, parent, false);
// 创建 ViewHolder 实例
ViewHolder holder = new ViewHolder(view);
return holder;
}
// 绑定 ViewHolder,用于对每个 item 进行赋值操作
@Override
public void onBindViewHolder(ViewHolder holder, int position){
// 获取当前项的 Food 实例
Food food = mFoodList.get(position);
TextView textView = holder.view.findViewById(R.id.tv_item);
ImageView imageView = holder.view.findViewById(R.id.iv_item);
textView.setText(food.getName());
imageView.setImageResource(food.getImageId());
}
// 获取 item 的数量
@Override
public int getItemCount(){
return mFoodList.size();
}
// 自定义的 ViewHolder 类,继承自 RecyclerView.ViewHolder
static class ViewHolder extends RecyclerView.ViewHolder{
View view;
ViewHolder(View view){
super(view);
this.view = view;
}
}
}
3. 布局管理器
在写好 MyAdapter 类之后,就是在 MainActivity 中使用 RecyclerView 了。我们到目前为止还剩下一个问题没解决,那就是既然提到了 RecyclerView 是作为 ListView 和 GridView 的替代者出现的,那么它是如何管理它的布局的呢?
答案就是调用 RecyclerView 实例的 setLayoutManager() 方法。setLayoutManager()方法接受一个 LayoutManager 类型的参数,通过这个参数来实现 RecyclerView 的各种各样的布局,前面所展示的布局都是在这个方法中进行设置的。下面就来介绍几个布局管理器类型:
1)LinearLayoutManager
如果我们要实现像 ListView 那样的垂直线性布局,就得使用 LinearLayoutManager 。代码如下所示:
// 获取 RecyclerView 的实例
mRecyclerView = (RecyclerView)findViewById(R.id.recycler_view);
// 线性布局管理器
LinearLayoutManager manager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(manager);
先构造 LinearLayoutManager 的实例 manager,它的默认 orientation 为 VERTICAL,与我们的需求正好一致,所以构造好之后直接将 manager 传入 setLayoutManager() 即可。最终效果如前面垂直线性布局所示。
而当我们需要实现横向线性布局时,只需要在第二句和第三句之间添加setOrientation()方法即可:
// 线性布局管理器
LinearLayoutManager manager = new LinearLayoutManager(MainActivity.this);
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(manager);
效果如前面水平线性布局所示。
2)GridLayoutManager
如果我们要实现像 GridView 那样的网格布局,就得使用 GridLayoutManager 。代码如下所示:
// 网格布局管理器
GridLayoutManager manager = new GridLayoutManager(MainActivity.this, 3);
mRecyclerView.setLayoutManager(manager);
GridLayoutManager 的构造函数的第二个参数类型是 int,表示列数,这里我们指定为 3,即显示三列的数据。效果如前面网格布局所示。
3)StaggeredGridLayoutManager
如果我们想实现瀑布流布局的效果的话,就得使用 StaggeredGridLayoutManager,代码如下所示:
// 瀑布流布局管理器
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(3,
StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(manager);
StaggeredGridLayoutManager 的构造方法第一个参数类型为int,表示列数,这里我们同样指定为3。第二个参数表示布局的方向,这里我们设定为垂直方向。实现效果如前面瀑布流布局所示。
4. 完整的 MainActivity 代码
这里我们以垂直线性布局为例,直接上代码:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private List<Food> foodList;
private MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化食物的数据
initData();
mRecyclerView = (RecyclerView)findViewById(R.id.recycler_view);
// 垂直线性布局
LinearLayoutManager manager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(manager);
// 将 foodList 传入 adapter 中
adapter = new MyAdapter(MainActivity.this, foodList);
mRecyclerView.setAdapter(adapter);
}
// 这里为了方便展示随便初始化了 20 个食物的数据
private void initData(){
foodList = new ArrayList<>();
for(int i = 0; i < 5; i++) {
Food food1 = new Food("Cake", R.drawable.cake);
Food food2 = new Food("Biscuit", R.drawable.biscuit);
Food food3 = new Food("Bread", R.drawable.bread);
Food food4 = new Food("Hamburger", R.drawable.hamburger);
foodList.add(food1);
foodList.add(food2);
foodList.add(food3);
foodList.add(food4);
}
}
}
到这里相信很多人都会看的比较明白了,在 MainActivity 中我们首先初始化了我们要展示的食物的数据,然后将布局设置为线性(默认为垂直布局)。然后我们会初始化adpater,它是我们自定义的 MyAdapter 类的实例,我们将初始好后的 foodList 作为参数传给它。最后,它会被作为参数传给 setAdapter() 方法。
至此,我们的代码就全部完成了!运行一下,效果如下图所示:
如果我们需要设置简单的分割线的话,可以添加一句代码:
mRecyclerView.addItemDecoration(new DividerItemDecoration(MainActivity.this,
DividerItemDecoration.VERTICAL));
效果如下图所示:
为了节省篇幅,其他的布局代码这里就不贴出来了,方法也很简单,无非是在setLayoutManager() 方法中传入不同的布局器参数,然后对 item_recycler_view 或数据进行简单的修改即可。
三、总结
对于 RecyclerView 的使用,可分为 4 步:
Step 1:向 build.gradle 中添加相应的依赖
Step 2:为 item 添加一个布局文件
Step 3:新建一个继承自 RecyclerView.Adapter 的 Adapter 类,并覆写 onCreateViewHolder()、onBindViewHolder() 和 getItemCount() 这三个方法。
Step 4:在 MainActivity 中,获取 RecyclerView 的实例,然后通过 setLayoutManager() 进行布局设置,通过 setAdapter() 设置适配器,然后就大功告成了!
最后,本篇博客是我写的第一篇博客,如果有写的不清楚或者不清晰的地方,望见谅!如果对于我的博客有任何想法建议的话,欢迎评论或私信!