RecyclerView基础用法

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

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

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

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

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

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

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

为什么您需要使用 RecyclerView 呢?

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

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

实现 RecyclerView

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

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

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

1 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4// 在 https://developer.android.google.cn/jetpack/androidx/releases/recyclerview 获得最新版本号 5def recyclerview_version = "1.1.0" 6 7implementation 'androidx.recyclerview:recyclerview:$recyclerview_version

RecyclerView 数据

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

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

1 <!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4<resources> 5 <string name="app_name">RecyclerSample</string> 6 <string-array name="flower_array"> 7 <item>Lily</item> 8 <item>Poppy</item> 9 <item>Sunflower</item> 10 <item>Freesia</item> 11 <item>Daisy</item> 12 <item>Rose</item> 13 <item>Daffodil</item> 14 <item>Lavender</item> 15 <item>Peony</item> 16 <item>Lilac</item> 17 <item>Dahlia</item> 18 <item>Tulip</item> 19 <item>Dandelion</item> 20 <item>Geranium</item> 21 <item>Gardenia</item> 22 <item>Rhododendron</item> 23 <item>Azalea</item> 24 </string-array> 25 26</resources>

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4class Datasource(val context: Context) { 5 fun getFlowerList(): Array<String> { 6 return context.resources.getStringArray(R.array.flower_array) 7 } 8}

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4override fun onCreate(savedInstanceState: Bundle?) { 5 super.onCreate(savedInstanceState) 6 setContentView(R.layout.activity_main) 7 val flowerList = Datasource(this).getFlowerList() 8}

RecyclerView 布局

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

1 <!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 xmlns:app="http://schemas.android.com/apk/res-auto"> 8 9 <androidx.recyclerview.widget.RecyclerView 10 android:id="@+id/recycler_view" 11 android:layout_width="match_parent" 12 android:layout_height="match_parent" 13 app:layoutManager="LinearLayoutManager"/> 14</FrameLayout>

表项布局

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

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 5 android:layout_width="match_parent" 6 android:layout_height="wrap_content"> 7 8 <TextView 9 android:id="@+id/flower_text" 10 android:layout_width="wrap_content" 11 android:layout_height="wrap_content" 12 android:textSize="32sp" /> 13</FrameLayout>

拆分 Adapter 类

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

创建 Adapter

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4class FlowerAdapter(val flowerList: Array<String>) { 5 6}

创建 ViewHolder

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4class FlowerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ 5 private val flowerTextView:TextView = itemView.findViewById(R.id.flower_text) 6 fun bind(word: String){ 7 flowerTextView.text = word 8 } 9}

继承 RecyclerView.Adapter

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4class FlowerAdapter(val flowerList: Array<String>) : 5 RecyclerView.Adapter<FlowerAdapter.FlowerViewHolder>() { 6 7}

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

重写 onCreateViewHolder()

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FlowerViewHolder { 5 val view = LayoutInflater.from(parent.context) 6 .inflate(R.layout.flower_item, parent, false) 7 return FlowerViewHolder(view) 8}

重写 onBindViewHolder()

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4override fun onBindViewHolder(holder: FlowerViewHolder, position: Int) { 5 holder.bind(flowerList[position]) 6}

重写 getItemCount()

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4override fun getItemCount(): Int { 5 return flowerList.size 6}

完成 Adapter 代码

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4class FlowerAdapter(val flowerList: Array<String>) : 5 RecyclerView.Adapter<FlowerAdapter.FlowerViewHolder>() { 6 7 // 描述表项视图并且将它放在 RecyclerView 中 8 class FlowerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 9 private val flowerTextView: TextView = itemView.findViewById(R.id.flower_text) 10 11 fun bind(word: String) { 12 flowerTextView.text = word 13 } 14 } 15 16 // 返回一个新的 ViewHolder 17 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FlowerViewHolder { 18 val view = LayoutInflater.from(parent.context) 19 .inflate(R.layout.flower_item, parent, false) 20 21 return FlowerViewHolder(view) 22 } 23 24 // 返回数据列表的长度 25 override fun getItemCount(): Int { 26 return flowerList.size 27 } 28 29 // 显示一个指定位置的数据 30 override fun onBindViewHolder(holder: FlowerViewHolder, position: Int) { 31 holder.bind(flowerList[position]) 32 } 33}

连接到 MainActivity

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

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

1<!-- Copyright 2019 Google LLC. 2 SPDX-License-Identifier: Apache-2.0 --> 3 4class MainActivity : AppCompatActivity() { 5 override fun onCreate(savedInstanceState: Bundle?) { 6 super.onCreate(savedInstanceState) 7 setContentView(R.layout.activity_main) 8 val flowerList = Datasource(this).getFlowerList() 9 val recyclerView: RecyclerView = findViewById(R.id.recycler_view) 10 recyclerView.adapter = FlowerAdapter(flowerList) 11 } 12}

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

点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )