第一行代码学习之 RecyclerView 的使用 [基础篇]

文章目录

    • 1. 前言
    • 2. 讲解
      • 2.1 引入 RecyclerView
      • 2.2 逻辑解释
        • 2.2.0 Person 类
        • 2.2.1 写好自定义 Adapter 基本框架
        • 2.2.2 自定义 ViewHolder
        • 2.2.3重写 Adapter 的抽象方法
        • 2.2.4 主函数
        • 2.2.4 总结
    • 3. 测试 demo

1. 前言

郭霖先生的《第一行代码》第三版已经出来了,系统讲解 Kotlin 开发 Android 的方法。我认为 Android 初学者(比如我)还是要从 Java 开始,故采用 Java 学习一下第一行代码第二版有关知识。
本文讲解 RecyclerView。

2. 讲解

2.1 引入 RecyclerView

在 app 模块下的 build.gradle 文件中需要导入以下依赖。如果是单纯手机开发,使用第一条 implementation 即可。

dependencies {
    implementation "androidx.recyclerview:recyclerview:1.1.0"
    // For control over item selection of both touch and mouse driven selection
    implementation "androidx.recyclerview:recyclerview-selection:1.1.0-rc01"
}

之后,在布局文件中可以用这样的办法使用 RecyclerView:


<LinearLayout xmlns: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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_veiw"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

LinearLayout>

2.2 逻辑解释

2.2.0 Person 类

为了测试,我们编写一个 Person 类,成员变量包含人物的姓名和图片。其中图片不用采用 ImageView 对象,只要给出图片的 id 即可。

public class Person {
    private String name;
    private int imageId;

    // 这个 imageId 实际上就是图片资源文件夹中的某一张图片的名字,系统会给图片分配一个 id,比如 kami.png 对应的 id 是 7759
    public Person(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    String getName() {
        return name;
    }

    int getImageId() {
        return imageId;
    }
}

2.2.1 写好自定义 Adapter 基本框架

设置布局有关的内容不做讲解。
RecyclerView 同样需要使用 Adapter 适配器来传数据。我们一般要自定义适配器,就要让自己创建的 Adapter 类继承 RecyclerView.Adapter。如下,创建一个人物适配器 PersonAdapter,声明框架代码如下:

public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.ViewHolder> {

    static class ViewHolder extends RecyclerView.ViewHolder {
            // ViewHolder 的逻辑
    }

    public PersonAdapter(List<Person> personList) {
    	// 构造函数
    }

}

2.2.2 自定义 ViewHolder

RecyclerView.Adapter 的泛型类型指定为 PersonAdapter 中的内部类 ViewHolder,需要继承 RecyclerView.ViewHolder 来使用。
ViewHolder 需要控制子项的布局,比如 这里就管理的是人物列表中的一张张卡片,所以构造函数需要传入一个 View 类型的参数,接着就可以通过这个参数调用 findViewById() 方法获取卡片中的各个元素。
给出了类成员和构造函数之后,自定义的 ViewHolder 类完成。
接着,PersonAdapter 类要重写 Recycler.View 中的方法,因为 RecyclerView.View 是抽象类,可以看到其声明原型如下:

/**
     * Base class for an Adapter
     *
     * 

Adapters provide a binding from an app-specific data set to views that are displayed * within a {@link RecyclerView}.

* * @param A class that extends ViewHolder that will be used by the adapter. */
public abstract static class Adapter<VH extends ViewHolder> { }

其泛型是 VH,代表的是一个从抽象类 ViewHolder 继承的一个 viewholder 类型。这里我们指定类型为继承了 RecyclerView.ViewHolder 的 ViewHolder 内部类,即 PersonAdapter.ViewHolder。这里为了防止与抽象类重名,写出了完整类名。

2.2.3重写 Adapter 的抽象方法

之后需要重写抽象类中的方法,分别是:

  1. onCreateViewHolder
  2. onBindViewHolder
  3. getItemCount

可以理解为,Adapter 适配器虽然要向 RecyclerView 传数据,但是我们写的自定义的 Adapter 本身不能识别给它的数据(子项的布局多种多样,Adapter 没有那么智能)。为此需要先做一个 ViewHolder,确定布局中的元素,将它们存在 ViewHolder 对象的成员变量中,Adapter 通过 ViewHolder 对象获取数据
PersonAdapter 需要重写的第一个方法,onCreateViewHolder,就是创建 ViewHolder 实例的,步骤是:
创建 View 对象,获取子项的布局,再将 View 对象传入 ViewHolder 构造函数,这样创建出的 ViewHolder 对象里就存储了各个子项的信息,再把 ViewHolder 对象返回。代码如下:

public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        // 传入子项布局构造 view
        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.person_layout, viewGroup, false);

        // 传入 view 构造 ViewHolder 对象并返回
       return new ViewHolder(view);
}

第二个方法 onBindViewHolder 是用来给 RecyclerView 子项赋值的,获取了 ViewHolder 对象后,一开始各个子项的属性(比如图片、名字等)并未被赋值,在这个函数里面就可以给它们指定值。**这个方法会在每个子项滚动到屏幕内时执行。**代码参考如下:

@Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Person person = personList.get(position);
        // 给 holder 的图片属性赋值,传入图片 id
        holder.personImage.setImageResource(person.getImageId());
        // 给 holder 的名字属性赋值,传入一个字符串
        holder.personName.setText(person.getName());
    }

最后一个方法返回的是列表中子项的总数。我们可以定义一个 Person 类列表提供数据,每一个列表元素都作为一个子项,那么这个方法只要返回列表的长度即可。

int getItemCount() {
		// 这个 list 是 适配器中的 Person 列表
        return List.size;
}

2.2.4 主函数

主函数比较简单,可以先创建一个 Person 列表,加载数据进去,接着获取 RecyclerView 实例,在设置一个 LinearLayoutManager 实例(子项的布局是线性布局)传给 RecyclerView,指定 RectclerView 为线性布局方式,接着创建一个 PersonAadapter 类型的适配器,传入 Person 列表,再给 RecyclerView 设置好这个适配器就可以了,代码展示如下:

public class MainActivity extends AppCompatActivity {

    private List<Person> personList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initPersons();
        RecyclerView recyclerView = findViewById(R.id.recycler_veiw);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        PersonAdapter adapter = new PersonAdapter(personList);
        recyclerView.setAdapter(adapter);
    }

    private void initPersons() {
        for (int i = 0; i < 9; i++) {
            Person kamiyama = new Person("神山識", R.drawable.kamiyama_satoru);
            personList.add(kamiyama);
            Person shari = new Person("夏莉", R.drawable.shari);
            personList.add(shari);
        }
    }
}

2.2.4 总结

RecyclerView 的难点在于理解自定义适配器的过程,这里做一下总结,也方便我之后复习:
自定义一个 Adapter 继承自 RecyclerView.Adapter,RecyclerView.Adapter 需指定一个 ViewHolder 用来获取子项内部的数据,将自己的 ViewHolder 定义为内部类比较方便;
自定义 Adapter 需要重写三个方法,onCreateViewHolder,用来创建一个 ViewHolder,参数类型为 View,代表子项的布局,布局 view 传给 ViewHolder 的构造函数,构造出一个 ViewHolder 对象并返回该对象;
onBindViewHodler 方法,获取了 ViewHolder 对象之后,要给其中的成员变量赋值,即给子项对应的各个布局参数赋值,为此 ViewHolder 每个对象都有一个 setResource 方法;
getItemCount 方法,返回的是 RecyclerView 子项的数目。

接着来看 ViewHolder 怎么写。Adapter 只是一个 存储数据的适配器,具体各个数据的对应还需要使用 ViewHolder。ViewHolder 的思路是,先获取子项的布局,再将子项的布局中的各个元素分别对应到 它的成员变量中(构造函数完成),这样,通过修改 ViewHolder 的成员变量,等于我们也对子项布局的内容进行了操作。

3. 测试 demo

上面的 Person 类的例子我补充了一下,做了一个简单的 demo 出来,放在了 GitHub 上。
点我直达
希望对大家有所帮助。感谢郭霖先生带我走进 Android 开发的大门。

你可能感兴趣的:(Android,界面相关)