RecyclerView基础用法

希望的天
• 阅读 1538

RecyclerView 是一款非常强大的 widget,它可以帮助您灵活地显示列表数据。当我开始学习 RecyclerView 的时候,我发现对于复杂的列表界面有很多资源可以参考,但是对于简单的列表展现就鲜有可参考的资源了。虽然 RecyclerView 的组成结构乍一看有些复杂,但是深入理解以后您会发现它其实非常简单明了。

本文会通过创建一个简单的 RecyclerView 实现一个列表来显示不同种类的花的名字。在实现的过程中,我也会将 RecyclerView 的每个部分揉碎了展现给大家,这样大家就可以在自己的应用中实现了。

RecyclerView 是 "何方神圣"?为什么选择它呢?

RecyclerView 是一个容器,它用于显示列表形式 (list) 或者网格形式 (grid) 的数据,比如文本或者照片。

当列表滑动的时候,实际上只有少量邻近的视图会显示在屏幕上。当视图滑出屏幕时,RecyclerView 会复用它并且填充新的数据。由于它是通过回收已有的结构而不是持续创建新的列表项,所以它可以有效提高应用的时间效率和空间效率。

RecyclerView基础用法

粉红色的方格表示屏幕上正在显示的表项,黄色的方格表示屏幕可视范围之外的表项是如何被回收并转为新的视图

为什么您需要使用 RecyclerView 呢?

  • RecyclerView 使用 ViewHolder 模式,这样做可以提高性能,因为它无需频繁调用 findViewById() 方法即可访问表项的视图;
  • RecyclerView 使用 LayoutManager,它支持纵向滑动的列表和横向滑动的列表,以及交错布局的列表和网格布局的列表。您还可以创建自定义的 LayoutManager;
  • RecyclerView 提供默认的表项动画以及自定义动画的入口。

总之,RecyclerView 兼顾了灵活性和个性化,所以它是功能强大的工具。

实现 RecyclerView

本文会为大家展示如何实现一个简单的 RecyclerView,用它来显示不同种类花的名称。下面的代码会使用 Kotlin 语言,但是 RecyclerView 也可以在 Java 语言中使用。

RecyclerView基础用法

首先在 Android Studio 里创建一个工程,并且使用 Empty Activity 模板。设置项目名称,并且选择 Kotlin 作为项目所用的语言。

RecyclerView基础用法

接下来在 app 级的 build.gradle 文件里引入 最新版本RecyclerView 依赖。

 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

// 在 https://developer.android.google.cn/jetpack/androidx/releases/recyclerview 获得最新版本号
def recyclerview_version = "1.1.0"

implementation 'androidx.recyclerview:recyclerview:$recyclerview_version 

RecyclerView 数据

RecyclerView 最重要的组成部分之一就是需要显示的数据。对于比较复杂的应用来说,数据可能是来自数据库或者来自于网络,不过这里我们简单使用字符串资源文件作为应用的数据源。

strings.xml 文件中,创建一个字符串数组来存放花的名称。

 <!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

<resources>
    <string name="app_name">RecyclerSample</string>
    <string-array name="flower_array">
        <item>Lily</item>
        <item>Poppy</item>
        <item>Sunflower</item>
        <item>Freesia</item>
        <item>Daisy</item>
        <item>Rose</item>
        <item>Daffodil</item>
        <item>Lavender</item>
        <item>Peony</item>
        <item>Lilac</item>
        <item>Dahlia</item>
        <item>Tulip</item>
        <item>Dandelion</item>
        <item>Geranium</item>
        <item>Gardenia</item>
        <item>Rhododendron</item>
        <item>Azalea</item>
    </string-array>

</resources> 

然后,创建一个类,名字为 Datasource,并且可以接收一个 Context 类型的参数。创建一个叫做 getFlowerList() 的函数,它负责返回花的名称列表。

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

class Datasource(val context: Context) {
    fun getFlowerList(): Array<String> {
        return context.resources.getStringArray(R.array.flower_array)
    }
} 

MainActivity.onCreate() 中,创建一个变量叫做 flowerList,然后将 getFlowerList() 的返回结果赋给它。

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  val flowerList = Datasource(this).getFlowerList()
} 

RecyclerView 布局

接下来,在 activity_main 布局文件中将 TextView 替换为 RecyclerView,并且将其 layoutManager 设置为 LinearLayoutManager。使用 LinearLayoutManager 意味着未来数据将以纵向列表或者横向列表的形式显示 (默认是纵向列表)。

 <!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   xmlns:app="http://schemas.android.com/apk/res-auto">

   <androidx.recyclerview.widget.RecyclerView
       android:id="@+id/recycler_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:layoutManager="LinearLayoutManager"/>
</FrameLayout> 

表项布局

RecyclerView基础用法

上面的示意图表示一个包含数据表项的 RecyclerView。在这里,组成 RecyclerView 的表项 (Item) 里会包含花的名称。

创建一个新的布局文件,将它命名为 flower_item,它用来决定每一个表项的显示布局。本例中布局仅需要显示一个鲜花的名称,所以这里只需要 TextView

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/flower_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="32sp" />
</FrameLayout> 

拆分 Adapter 类

接下来是 RecyclerView 的重头戏了,也就是 ViewHolderAdapter 类。ViewHolder 负责存储 RecyclerView 中每一个单独的表项所需要显示的信息。RecyclerView 仅需要创建当前所显示的表项数量的 ViewHolder 外加缓存中的几个 ViewHolder 即可。随着用户滑动屏幕,ViewHolder会被回收 (使用新数据进行填充),已有的表项会在一端消失,并且在另一端显示一个新的表项。Adapter 类从数据源获得数据,并且将数据传递给正在更新其所持视图的 ViewHolder。下图显示了 RecyclerView、Adapter、ViewHolder 和数据之间的协作关系。

RecyclerView基础用法

创建 Adapter

创建一个叫做 FlowerAdapter 的类,所需显示的列表数据作为该类的参数。

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

class FlowerAdapter(val flowerList: Array<String>) {

} 

创建 ViewHolder

创建一个叫做 FlowerViewHolder 的内部类,并且它可以接收一个 itemView 作为参数。在 ViewHolder 中,创建一个变量来引用 TextView,然后将它指向表项布局里对应的视图。然后创建 bind() 函数,它用来将花的名字 (字符串) 和携带数据的 UI (flowerTextView) 关联起来。bind() 函数接收传入的字符串,并且将字符串作为 flowerTextView 的文本内容。

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

class FlowerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
  private val flowerTextView:TextView = itemView.findViewById(R.id.flower_text)
  fun bind(word: String){
    flowerTextView.text = word
  }
} 

继承 RecyclerView.Adapter

更新 FlowerAdapter 的类定义,使其继承 RecyclerView.Adapter 类,并且将 FlowerViewHolder作为参数传入。

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

class FlowerAdapter(val flowerList: Array<String>) :
    RecyclerView.Adapter<FlowerAdapter.FlowerViewHolder>() {

} 

重写 RecyclerView.Adapter 的类需要重写三个方法 onCreateViewHolder()onBindViewHolder()getItemCount()

重写 onCreateViewHolder()

ViewHolder 创建的时候会调用该方法。在该方法里进行初始化和填充 RecyclerView 中的表项视图。该视图使用前面我们创建的用于显示文本的布局。

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FlowerViewHolder {
  val view = LayoutInflater.from(parent.context)
  .inflate(R.layout.flower_item, parent, false)
  return FlowerViewHolder(view)
} 

重写 onBindViewHolder()

onBindViewHolder() 被调用的时候,会传入参数 ViewHolder 和一个位置 (position),它表示在 flowerList 中所绑定的表项的位置。该位置可以用于提取表项所需的数据,并且将数据传递给 ViewHolder 来使数据绑定到对应的 UI。

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

override fun onBindViewHolder(holder: FlowerViewHolder, position: Int) {
  holder.bind(flowerList[position])
} 

重写 getItemCount()

RecyclerView 显示一个列表,所以它需要知道列表里共有多少项。由于 flowerList 就是数据源,所以直接返回它的长度即可。

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

override fun getItemCount(): Int {
  return flowerList.size
} 

完成 Adapter 代码

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

class FlowerAdapter(val flowerList: Array<String>) :
    RecyclerView.Adapter<FlowerAdapter.FlowerViewHolder>() {

    // 描述表项视图并且将它放在 RecyclerView 中
    class FlowerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val flowerTextView: TextView = itemView.findViewById(R.id.flower_text)

        fun bind(word: String) {
            flowerTextView.text = word
        }
    }

    // 返回一个新的 ViewHolder
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FlowerViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.flower_item, parent, false)

        return FlowerViewHolder(view)
    }

    // 返回数据列表的长度
    override fun getItemCount(): Int {
        return flowerList.size
    }

    // 显示一个指定位置的数据
    override fun onBindViewHolder(holder: FlowerViewHolder, position: Int) {
        holder.bind(flowerList[position])
    }
} 

连接到 MainActivity

我们已经创建了布局、数据列表和 adapter。现在我们可以将 RecyclerView 添加到 MainActivity,并且将 Adapter 赋值给它。

定义一个变量叫做 recyclerView,然后将 activity_main 中的 RecyclerView 赋值给 recyclerView。将 FlowerAdapter 作为您 recyclerView 的 adapter。

<!-- Copyright 2019 Google LLC. 
   SPDX-License-Identifier: Apache-2.0 -->

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val flowerList = Datasource(this).getFlowerList()
        val recyclerView: RecyclerView = findViewById(R.id.recycler_view)
        recyclerView.adapter = FlowerAdapter(flowerList)
    }
} 

现在我们运行一下,然后看看它操作起来如何:

RecyclerView基础用法

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这