RecyclerView的点击事件
RecyclerView中没有提供类似与setOnItemClickListener()这样的注册监听方法,而需要我们自己给子项具体的View去注册点击事件。相比与ListView来说,RecyclerView的功能更加强大,不仅可以实现对点击子项的响应,而且对子项的每一个view都可以轻松的实现点击响应。
下面通过两种方法来实现:
(一)在适配器的onBindViewHolder方法中去添加响应事件
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
...
//点击事件(对子项的监听),若想监听子项中的view,将itemView改成对于的Id即可
holder.itemView.setOnClickListener {
val index = holder.layoutPosition
...
}
}
Demo:这个示例用RecyclerView来显示歌曲列表,点击列表子项后通过Toast弹出具体点击了哪一首歌曲。
1.activity_main.xml:直接引入一个recyclerView控件即可
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
2.item子项的布局:这里主要用于显示:图片,歌手以及歌曲名字。用了cardView来形成圆角效果
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="100dp"
app:cardCornerRadius="10dp"
app:cardElevation="1dp"
app:cardUseCompatPadding="true">
<ImageView
android:id="@+id/songImage"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="2dp"
/>
<LinearLayout
android:layout_width="276dp"
android:layout_height="75dp"
android:layout_gravity="end"
android:orientation="vertical">
<TextView
android:id="@+id/song"
android:layout_width="266dp"
android:layout_height="40dp"
android:textColor="#0800ff"
android:textSize="20sp" />
<TextView
android:id="@+id/singer"
android:layout_width="264dp"
android:layout_height="29dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
3.res/values下的arrays.xml中存放歌曲信息
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="songName">
<item>晴天</item>
<item>我的一个道姑朋友</item>
<item>城南花已开</item>
</string-array>
<string-array name="singer">
<item>周杰伦</item>
<item>双笙</item>
<item>三亩地</item>
</string-array>
<integer-array name="songImage">
<item>@mipmap/sunny_day</item>
<item>@mipmap/a_friend_of_mine</item>
<item>@mipmap/city</item>
</integer-array>
</resources>
4.歌曲类
data class Song(var singer:String, val song:String, val imageId:Int)
5.全局Context的设置:因为要Toast是需要Context环境的。而在适配器类中是没有Context环境的。因此可以写一个全局Context的获取类MyApplication。
class MyApplication : Application() {
companion object{
lateinit var context : Context
}
override fun onCreate() {
super.onCreate()
context = applicationContext
}
}
同时需要在AndroidManfest.xml中添加:Android:name=".MyApplication"
6.适配器的实现(在OnBindViewHolder中实现了点击事件)
class SongAdapter(val songList:List<Song>):
RecyclerView.Adapter<SongAdapter.ViewHolder>() {
inner class ViewHolder(view: View):RecyclerView.ViewHolder(view){
val songImage : ImageView = view.findViewById(R.id.songImage)
val song : TextView = view.findViewById(R.id.song)
val singer : TextView = view.findViewById(R.id.singer)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.song_item,parent,false)
return ViewHolder(view)
}
override fun getItemCount() = songList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val value = songList[position]
holder.songImage.setImageResource(value.imageId)
holder.song.text = value.song
holder.singer.text = value.singer
//点击事件
holder.itemView.setOnClickListener {
val id = holder.layoutPosition
val name = songList[id]
Toast.makeText(MyApplication.context,"点击了歌曲${name}",Toast.LENGTH_SHORT).show()
}
}
}
7.MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
val adapter = SongAdapter(getSongs())
recyclerView.adapter = adapter
}
//加载数据
private fun getSongs():List<Song>{
val songList = ArrayList<Song>()
val songName = resources.getStringArray(R.array.songName)
val singer = resources.getStringArray(R.array.singer)
val songImage = resources.obtainTypedArray(R.array.songImage)
for( i in 0..songName.size-1){
val temp = Song(singer[i],
songName[i],
songImage.getResourceId(i,R.mipmap.sunny_day))
songList.add(temp)
}
return songList
}
}
(二)写回调方法
若想在点击后实现AlertDialog,但是AlertDialog是需要依附于Activity的。全局的Context是不能用的。这时候就可以写一个回调方法,在MainActivity中来实现事件的监听。
修改适配器类的代码(修改处写了注释)
package com.example.recyclerviewtest
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
class SongAdapter(val songList:List<Song>):
RecyclerView.Adapter<SongAdapter.ViewHolder>() {
//1.定义接口类型的成员数据
private var myItemClickListener : OnItemClickListener ?= null
//2.定义接口
interface OnItemClickListener{
fun onItemClick(position:Int)
}
//3.set方法
fun setOnItemClickListener(onItemClickListener : OnItemClickListener?){
myItemClickListener = onItemClickListener
}
inner class ViewHolder(view: View):RecyclerView.ViewHolder(view){
val songImage : ImageView = view.findViewById(R.id.songImage)
val song : TextView = view.findViewById(R.id.song)
val singer : TextView = view.findViewById(R.id.singer)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.song_item,parent,false)
return ViewHolder(view)
}
override fun getItemCount() = songList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val value = songList[position]
holder.songImage.setImageResource(value.imageId)
holder.song.text = value.song
holder.singer.text = value.singer
//4.传入position
holder.itemView.setOnClickListener {
myItemClickListener!!.onItemClick(position)
}
}
}
在MainActivity中
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
val songList = getSongs()
val adapter = SongAdapter(songList)
recyclerView.adapter = adapter
adapter.setOnItemClickListener(object:SongAdapter.OnItemClickListener{
override fun onItemClick(position: Int) {
AlertDialog.Builder(this@MainActivity).apply {
setTitle("test")
setMessage("点击了${songList[position]}")
setCancelable(false)
setPositiveButton("OK"){dialog, which -> }
setNegativeButton("Cancel"){dialog, which -> }
show()
}
}
})
}