参照 kotlin官网:使用 RecyclerView 显示可滚动列表的 案例实现
功能:采用RecyclerView 空间实现图片和文字的滚动浏览。
在下图显示的序列中,可以看到一个填充了数据 ABC
的视图。当该视图滚动出屏幕之后,RecyclerView
会重复使用该视图来显示新数据 XYZ
。
RecyclerView
显示数据列表?RecyclerView
配合使用以自定义各列表项的外观?下面内容添加到项目中。
打开 app > res > values > strings.xml
将需要显示的语句输入string
Affirmations
1I am strong.
2 I believe in myself.
3 Each day is a new opportunity to grow and be a better version of myself.
4 Every challenge in my life is an opportunity to learn from.
5 I have so much to be grateful for.
6 Good things are always coming into my life.
7 New opportunities await me at every turn.
8 I have the courage to follow my heart.
9 Things will unfold at precisely the right time.
10 I will be present in all the moments that this day brings.
您已添加了字符串资源,可以在代码中将其引用为 R.string.affirmation1
或 R.string.affirmation2
图中显示了三个大的软件包(文件夹):一个用于您的代码 (com.example.affirmations),另外两个用作测试文件(com.example.affirmations (androidTest) 和 com.example.affirmations (test))。
软件包的名称由几个单词组成,单词间以句点进行分隔。
在弹出式窗口中,将 model 附加到建议的软件包名称末尾,创建了 model文件夹。
类似的, 创建adapter,data 软件包。
右键点击 com.example.affirmations.model 软件包,然后依次选择 New > Kotlin File/Class。
Affirmation
作为类的名称。系统将在 model
软件包中创建一个名为 Affirmation.kt
的新文件。data
关键字,使 Affirmation
成为数据类。这样做会出错,因为数据类必须至少定义一个属性。package com.example.affirmations.model
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
/*
在类定义前添加 data 关键字,使 Affirmation 成为数据类。
在创建 Affirmation 的实例时,您需要传入自我肯定话语字符串的资源 ID。资源 ID 是一个整数。
*/
data class Affirmation(@StringRes val stringResourceId:Int,
@DrawableRes val imageResourceId :Int) {
}
准备数据是一项需要单独处理的工作,因此请将 Datasource
类放在单独的 data 软件包中。
data
作为软件包名称的最后一部分。data
软件包,然后选择 new Kotlin File/Class。Datasource
作为类名称。Datasource
类中,创建一个名为 loadAffirmations()
的函数。loadAffirmations()
函数需要返回 Affirmations
的列表。为此,您可以创建一个列表,并使用每个资源字符串的 Affirmation
实例填充该列表。
List
声明为 loadAffirmations()
方法的返回值类型。loadAffirmations()
的主体中,添加 return
语句。return
关键字之后,调用 listOf<>()
创建一个 List
。<>
内,将列表项的类型指定为 Affirmation
。根据需要导入 com.example.affirmations.model.Affirmation
。Affirmation
,传入 R.string.affirmation1
作为资源 ID,如下所示。由于类Affirmation 包括文本和图片,因此参数为这2个的id。后面将用于文本和图片的显示。
package com.example.affirmations.data
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class Datasource{
fun loadAffirmations(): List {
return listOf(
Affirmation(R.string.Affirmation1, R.drawable.image1), // THERE need comma ,, between item
Affirmation(R.string.Affirmation2,R.drawable.image2),
Affirmation(R.string.Affirmation3,R.drawable.image3),
Affirmation(R.string.Affirmation4, R.drawable.image4),
Affirmation(R.string.Affirmation5, R.drawable.image5),
Affirmation(R.string.Affirmation6,R.drawable.image6),
Affirmation(R.string.Affirmation7,R.drawable.image7),
Affirmation(R.string.Affirmation8,R.drawable.image8),
Affirmation(R.string.Affirmation9,R.drawable.image9),
Affirmation(R.string.Affirmation10,R.drawable.image10)
)
}
}
您将设置一个 RecyclerView
来显示 Affirmations
的列表。
(这个有点不好理解:实际就是一个窗口 用recyclerview显示文本和图片,由于图片比较大,因此各列之间会滚动来显示)
Affirmations 应用由一个名为 MainActivity
的 activity 及其名为 activity_main
.xml
的布局文件组成。首先,您需要将 RecyclerView
添加到 MainActivity
的布局中。
activity_main.xml
(app > res > layout > activity_main.xml)。当前布局使用的是 ConstraintLayout
。如果想在布局中放置多个子视图,那么 ConstraintLayout
就是理想而又灵活的选择。不过,因为您的布局只有一个子视图 RecyclerView
,所以您可以切换到更简单的名为 FrameLayout
的 ViewGroup
,这才是只包含一个子视图时应该使用的选择。
在 XML 文件中,将 ConstraintLayout
替换为 FrameLayout
。完成后的布局应如下所示。
activity_main.xml
为了能够滚动浏览超出屏幕长度的垂直项目列表,您需要添加一个垂直滚动条。
在 RecyclerView
内,添加设为 vertical
的 android:scrollbars
属性。
RecyclerView
中的每个列表项都有自己的布局,您可以在单独的布局文件中定义这些布局。由于您只需要显示字符串,因此可将 TextView
用于列表项布局。
list_item.xml
的空 File。list_item.xml
。id
为 item_title
的 TextView
。layout_width
和 layout_height
添加 wrap_content
,如下面的代码所示。这里使用Matrial属性
您也可以使用 File > New > Layout Resource File,将 File name 设为 list_item.xml
,并以 TextView
作为 Root element。然后,更新生成的代码以匹配上面的代码。
新版本的图有区别,记得更改为TextView。
adapter
作为软件包名称的最后一部分。adapter
软件包,然后依次选择 New > Kotlin File/Class。ItemAdapter
作为类名称,完成创建操作,系统将打开 ItemAdapter.kt
文件。您需要将一个参数添加到 ItemAdapter
的构造函数中,以便将语句列表传入 Adapter。
ItemAdapter
的构造函数中,该参数是名为 dataset
、类型为 List
的 val
。根据需要导入 Affirmation
。dataset
仅在此类中使用,因此请将其设为 private
。ItemAdapter.kt
import com.example.affirmations.model.Affirmation
class ItemAdapter(private val dataset: List) {
}
ItemAdapter
的构造函数中,该参数是名为 context
、类型为 Context
的 val
。请将其作为构造函数中的第一个参数。class ItemAdapter(private val context: Context, private val dataset: List) {
}
详细内容如下:
package com.example.affirmations.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
/**
* Adapter for the [RecyclerView] in [MainActivity]. Displays [Affirmation] data object.
* 这个申明太奇怪,怎么能将class 申明类型为 类里的成员 ItemAdapter.ItemViewHolder
*/
class ItemAdapter(
private val context: Context,
private val dataset: List
):RecyclerView.Adapter( ){
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder.
// Each data item is just an Affirmation object.
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder( view){
val textView: TextView= view.findViewById(R.id.item_title) // textview--item_title
val imageView: ImageView = view.findViewById((R.id.item_image))
}
/**
* Create new views (invoked by the layout manager)
* 在 onCreateViewHolder() 方法中,从提供的上下文(parent 的 context)中获取 LayoutInflater 的实例。
* 布局膨胀器知道如何将 XML 布局膨胀为视图对象的层次结构。
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
// create a new view
// 奇怪,将以下参数改为true, 再改为false, 所有affirmation的文本就能显示。之前只能显示一个。
/**
* public View inflate (XmlPullParser parser,
ViewGroup root,
boolean attachToRoot)
parser XmlPullParser: XML dom node containing the description of the view hierarchy.
root ViewGroup: Optional view to be the parent of the generated hierarchy (if attachToRoot is true), or else simply an object that provides a set of LayoutParams values for root of the returned hierarchy (if attachToRoot is false.) This value may be null.
attachToRoot boolean: Whether the inflated hierarchy should be attached to the root parameter? If false, root is only used to create the correct subclass of LayoutParams for the root view in the XML.
*/
val adapterLayout= LayoutInflater.from(parent.context).inflate(R.layout.list_item,parent,false)
return ItemViewHolder(adapterLayout)
}
/**
* Replace the contents of a view (invoked by the layout manager)
* 调用 context.resources.getString() 并传入字符串资源 ID。返回的字符串可在 holder ItemViewHolder 中设为 textView 的 text
*/
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val item= dataset[position]
holder.textView.text = context.resources.getString(item.stringResourceId)
holder.imageView.setImageResource(item.imageResourceId)
}
/**
* Return the size of your dataset (invoked by the layout manager)
*/
override fun getItemCount(): Int {
return dataset.size
}
}
class ItemAdapter(
private val context: Context,
private val dataset: List
) : RecyclerView.Adapter() {
class ItemViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.item_title)
}
}
您会看到一条错误消息,因为您需要从 RecyclerView.Adapter
实现一些抽象方法。
ItemAdapter
上,然后按 Command+I(在 Windows 上,则请按 Control+I)。系统将列出您需要实现的方法:getItemCount()
、onCreateViewHolder()
和 onBindViewHolder()
。使用 Shift+click 将三个函数全部选中,然后点击 OK。
以上内容 做起来的难以理解,kotlin的函数封装太多。只能去适应。
您需要使用 Datasource
和 ItemAdapter
类在 RecyclerView
中创建和显示列表项。您可以在 MainActivity
中执行此操作。
MainActivity.kt
。MainActivity,
中,转到 onCreate()
方法。在调用 setContentView(R.layout.activity_main).
之后,插入以下步骤中所述的新代码。Datasource
的实例,并对其调用 loadAffirmations()
方法。将返回的语句列表存储在名为 myDataset
的 val
中。val myDataset = Datasource().loadAffirmations()
recyclerView
使用您创建的 ItemAdapter
类,请创建一个新的 ItemAdapter
实例。ItemAdapter
应该有两个参数:此 activity 的上下文 (this
) 和 myDataset
中的自我肯定话语。ItemAdapter
对象分配给 recyclerView
的 adapter
属性。recyclerView.adapter = ItemAdapter(this, myDataset)
由于 activity 布局中的 RecyclerView
布局大小是固定的,因此您可以将 RecyclerView
的 setHasFixedSize
参数设为 true
总的代码如下:
package com.example.affirmations
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.affirmations.adapter.ItemAdapter
import com.example.affirmations.data.Datasource
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//创建 Datasource 的实例,并对其调用 loadAffirmations() 方法。将返回的自我肯定话语列表存储在名为 myDataset 的 val 中。
// Initialize data.
val myDataset = Datasource().loadAffirmations()
//创建一个名为 recyclerView 的变量,并使用 findViewById() 查找对布局中 RecyclerView 的引用。
val recylceView = findViewById(R.id.recycler_view)
recylceView.adapter = ItemAdapter(this,myDataset)
// Use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
/**
* 虽然显示了内容,但还是没有搞清楚内部的逻辑关系
*/
recylceView.setHasFixedSize(true)
//val textView: TextView = findViewById(R.id.textView)
//textView.text = Datasource().loadAffirmations().size.toString()
}
}
图片地址:下载图片
将图片文件下载到您的计算机上。应该有十张图片,应用中的每句话语各有一张图片。这些文件的名称应该是从 image1.jpg
到 image10.jpg
。
在 Android Studio 中,将图片从您的计算机复制到项目的 res > drawable 文件夹 (app/src/main/res/drawable
) 中。一旦将这些资源添加到应用,您便能够使用资源 ID(如 R.drawable.image1
)从代码访问这些图片。(您可能必须重建代码,才能让 Android Studio 找到图片。)
运行app, 结果如下:
可以修改图片显示列
如何实现点击图片放大显示呢?
您将更新应用图标,需要把原来的图标删除。
drawable/ic_launcher_background.xml
和 drawable-v24/ic_launcher_foreground.xml
文件,因为这些文件用于以前的应用图标。您可以取消选中 Safe delete (with usage search) 框。4.在 Configure Image Asset 窗口中,确保选择了 Foreground layer。
5.在它下面,找到 Path 标签。
6.点击 Path 文本框内的文件夹图标。
7.找到并打开您下载到计算机上的 ic_launcher_foreground
.xml
文件。
8.切换到 Background Layer 标签页。
9.点击 Path 文本框内的 Browse 图标。
10.在计算机上查找并打开 ic_launcher_background
.xml
文件。不需要进行其他更改。
11.点击 Next。
模拟器安装的图标已经变化。
color
#FFBB86FC
#FF6200EE
#FF3700B3
#FF03DAC5
#FF018786
#FF000000
#FFFFFFFF
#FF90CAF9
#FF2196F3
#FF1976D2
#1B5E20
#003300
#A5D6A7
#0288D1
#005B9F
#81D4FA
theme.xml