RecyclerView onClickListener 与 DiffUtil
RecyclerView onClickListener with DiffUtil
如何使用 DiffUtil 回调处理 RecyclerView 的 onClick?以及如何更改 recyclerview 中所选项目的背景颜色?我有两个 RecyclerViews 合二为一 Activity。当用户单击 RecyclerView A 中的项目时,RecyclerView B 中会发生一些事情。
这是class
import androidx.room.ColumnInfo
data class SkladTuple(
@ColumnInfo(name = "sklad") val sklad: Int?,
@ColumnInfo(name = "reg") val reg: Int?
)
这是适配器:
class SkladAdapter: ListAdapter<SkladTuple, SkladAdapter.PolozkaViewHolder>(DiffCallback())
{
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PolozkaViewHolder {
val binding = SkladyItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return PolozkaViewHolder(binding)
}
override fun onBindViewHolder(holder: PolozkaViewHolder, position: Int) {
val currentItem = getItem(position)
holder.bind(currentItem)
}
class PolozkaViewHolder(private val binding: SkladyItemBinding): RecyclerView.ViewHolder(binding.root){
fun bind(polozkaSklad: SkladTuple){
binding.apply {
tvSklad.text = polozkaSklad.sklad.toString()
tvRegal.text = polozkaSklad.reg.toString()
}
}
}
class DiffCallback: DiffUtil.ItemCallback<SkladTuple>(){
override fun areItemsTheSame(oldItem: SkladTuple, newItem: SkladTuple) =
oldItem.sklad == newItem.sklad
override fun areContentsTheSame(oldItem: SkladTuple, newItem: SkladTuple) =
oldItem == newItem
}
}
这是Activity
@AndroidEntryPoint
class DokladActivity : AppCompatActivity() {
private val skladViewModel: SkladViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityDokladBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btVybratDoklad.setOnClickListener{
openActivity(binding.root)
}
val skladAdapter = SkladAdapter()
val dokladAdapter = DokladAdapter()
binding.apply {
recyclerViewSklady.apply {
adapter = skladAdapter
layoutManager = LinearLayoutManager(this@DokladActivity)
}
skladViewModel.skladyPolozky.observe(this@DokladActivity) {
skladAdapter.submitList(it)
Log.d("Doklad", skladAdapter.currentList.toString())
}
recyclerViewDoklady.apply {
adapter = dokladAdapter
layoutManager = LinearLayoutManager(this@DokladActivity)
}
skladViewModel.dokladyPolozky.observe(this@DokladActivity){
dokladAdapter.submitList(it)
Log.d("Doklad", dokladAdapter.currentList.toString())
}
}
}
fun openActivity(view: View){
val intent = Intent(this,PolozkaActivity::class.java )
startActivity(intent)
}
}
这是 ViewModel
@HiltViewModel
class SkladViewModel @Inject constructor(
repository: SybaseRepository
): ViewModel(){
val skladyPolozky = repository.getAllSkladFromPolozka().asLiveData()
val dokladyPolozky = repository.getAllHlavickyToDoklad().asLiveData()
}
这是布局 - 我有两个回收视图。当用户点击 recyclerview A 中的项目时,recyclerview B 中会发生一些事情
<?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">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.02" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.7" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.25" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.9" />
<TableLayout
android:stretchColumns="1,2"
android:layout_margin="8dp"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/guideline10"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline8">
<TableRow>
<TextView
android:text="SKLAD"
android:textSize="16dp"
android:textStyle="bold"
android:padding="10dp"
android:layout_gravity="center"
android:layout_column="1"/>
<TextView
android:text="REGAL"
android:textSize="16dp"
android:textStyle="bold"
android:padding="10dp"
android:layout_gravity="center"
android:layout_column="1"/>
</TableRow>
<androidx.recyclerview.widget.RecyclerView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recycler_view_sklady"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/sklady_item"
/>
</TableLayout>
<TableLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:stretchColumns="1,2,3,4,5"
app:layout_constraintBottom_toTopOf="@+id/guideline11"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline10"
>
<TableRow>
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="U"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="DOKL"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="ODB"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="ORG"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="DATUM"
android:textSize="16dp"
android:textStyle="bold" />
</TableRow>
<androidx.recyclerview.widget.RecyclerView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recycler_view_doklady"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/doklady_item"/>
</TableLayout>
<Button
android:id="@+id/bt_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:text="Zpět"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline12" />
<Button
android:id="@+id/bt_vybrat_doklad"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:text="Vybrat doklad"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline12" />
<TextView
android:id="@+id/textView2"
android:layout_width="209dp"
android:layout_height="50dp"
android:layout_marginStart="24dp"
android:layout_marginTop="16dp"
android:text="TextView"
app:layout_constraintBottom_toTopOf="@+id/guideline12"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline11" />
</androidx.constraintlayout.widget.ConstraintLayout>
How is it possible to ...
你有一个 ViewModel,它公开了两个可观察的 liveData 和你的 RecyclerViews 需要的列表(两个适配器,两个列表)。
决定列表 A 的项目 1 被点击并因此列表 B 的项目 N 必须更改其背景的逻辑绝对在 回收站视图的范围之外、适配器、Activity,甚至可能是 ViewModel。
最终,当发生数据突变时(您点击了项目 1),您会收到此事件,对其采取行动(又名:将其发送到 Viewmodel -> Repository ->转换数据 -> 使用变异数据发布新列表。
最终,您的 ViewModel 将从存储库接收新数据,并将更新您的 activity 正在观察的 LiveData,这将导致适配器提交新数据,您的DiffUtils 将启动,导致 Adapter 重新绑定修改后的视图。
更新
根据您链接的 question/answer 和您的评论,我认为这值得进一步评论。
此人说:“处理适配器上的点击或使用界面都不是一个好主意”,然后继续“处理”点击,和 使用了一个匿名函数(所以它可能是一个用于测试目的的接口,但它却使它成为一个“高阶函数”)。
这和我描述的原理完全一样,只是接口更容易理解。
想想这样的责任:
ViewHolder:它对数据、回收器视图、适配器等一无所知。但它可以直接访问您的列表中的每个“row/column”。它拥有视图,并且可以根据它提供的数据来操纵它们,并告诉它与所需的视图一起“保存”。它不创建视图(它被告知)但它有它们。关于点击,所有这一切都可以做,要么公开一个视图(这样一个点击监听器可以由外部的人设置)或者简单地委托它。
适配器:除了它们的类型(如果使用)以及如何创建 viewHolders 和“绑定”它们之外,它对视图一无所知。所以它介于两者之间,但它确实可以访问提供给它的数据源(您提供的列表)并且它确实可以访问它创建的每个“视图持有者”;它或多或少知道屏幕上的内容,并且可以将位置映射到数据。
RecyclerView/Fragment/ViewModel:他们不知道适配器内部发生了什么(他们也不应该知道),但他们主要对点击(或事件)发生的时间感兴趣,因此他们大概可以对此做些什么。
基于所有这些,让我们看看 (与我的建议相比):
- Adapter 的构造函数修改为接收一个函数:
(private val onSelect: (YourDataType?) -> Unit)
我通常定义一个接口:
interface SomethingClickListener {
fun onSomethingICaredForHappened(something: Something)
}
并将其传递给我的适配器,但思路是一样的;我更喜欢接口,因为它更容易使用具体类型的依赖注入(并且更容易测试),但我相信这只是个人偏好。
class YourAdapter(private val clickListener: SomethingClickListener)
- adapter内部也是一样的原理。您需要在您希望被点击的视图上设置实际的点击侦听器(或者如果您希望整个“行”都可点击,则设置整个 itemView)。
通过简单地使用点击侦听器的匿名实现并捕获发送到绑定方法的值(这很好),您可以(或想在其中做更多的事情)来获得链接的答案。因此,您可以使用另一个界面或那样做,本质上,想法是相同的,您 沿 传递点击事件。
binding.root.setOnClickListener {
onSelect(yourDataType)
}
所以它将 dataType
直接传递给 onSelect
(这是提供给适配器的函数)。在这个阶段,其中唯一的逻辑是您附加与被点击的 viewBinding 关联的“数据”,这是 adapter/viewholder 可以 并且应该 供应。
在这个 onSelect
之后发生的事情是你的 fragment/activity 收到这个,然后你应该调用你的 ViewModel 说:
viewModel.thisThingWasClicked(theThingYouReceived)
你明白了......
我有一段时间没有更新它了(我想我是 3 年前在 Java 中最初写的,然后我天真地将它转换为 Kt)除了更新库并确保它仍然可以编译,但是您可以看到“双接口方法”(有点老派,现在可以通过 Kotlin 获得高阶函数),但仍然是相同的方法。
看看这个项目(特别是 adapter。
注意它接受 ThingClickListener
,但在内部使用 ToggleListener
在 ViewHolder 和 Adapter 之间进行对话。
最后,这可以简化为少用一个界面。
我希望这能澄清我的想法。
请注意,ViewHolder 和 Adapter 除了处理 Click 侦听器和绑定正确的数据之外没有任何责任。
如何使用 DiffUtil 回调处理 RecyclerView 的 onClick?以及如何更改 recyclerview 中所选项目的背景颜色?我有两个 RecyclerViews 合二为一 Activity。当用户单击 RecyclerView A 中的项目时,RecyclerView B 中会发生一些事情。
这是class
import androidx.room.ColumnInfo
data class SkladTuple(
@ColumnInfo(name = "sklad") val sklad: Int?,
@ColumnInfo(name = "reg") val reg: Int?
)
这是适配器:
class SkladAdapter: ListAdapter<SkladTuple, SkladAdapter.PolozkaViewHolder>(DiffCallback())
{
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PolozkaViewHolder {
val binding = SkladyItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return PolozkaViewHolder(binding)
}
override fun onBindViewHolder(holder: PolozkaViewHolder, position: Int) {
val currentItem = getItem(position)
holder.bind(currentItem)
}
class PolozkaViewHolder(private val binding: SkladyItemBinding): RecyclerView.ViewHolder(binding.root){
fun bind(polozkaSklad: SkladTuple){
binding.apply {
tvSklad.text = polozkaSklad.sklad.toString()
tvRegal.text = polozkaSklad.reg.toString()
}
}
}
class DiffCallback: DiffUtil.ItemCallback<SkladTuple>(){
override fun areItemsTheSame(oldItem: SkladTuple, newItem: SkladTuple) =
oldItem.sklad == newItem.sklad
override fun areContentsTheSame(oldItem: SkladTuple, newItem: SkladTuple) =
oldItem == newItem
}
}
这是Activity
@AndroidEntryPoint
class DokladActivity : AppCompatActivity() {
private val skladViewModel: SkladViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityDokladBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btVybratDoklad.setOnClickListener{
openActivity(binding.root)
}
val skladAdapter = SkladAdapter()
val dokladAdapter = DokladAdapter()
binding.apply {
recyclerViewSklady.apply {
adapter = skladAdapter
layoutManager = LinearLayoutManager(this@DokladActivity)
}
skladViewModel.skladyPolozky.observe(this@DokladActivity) {
skladAdapter.submitList(it)
Log.d("Doklad", skladAdapter.currentList.toString())
}
recyclerViewDoklady.apply {
adapter = dokladAdapter
layoutManager = LinearLayoutManager(this@DokladActivity)
}
skladViewModel.dokladyPolozky.observe(this@DokladActivity){
dokladAdapter.submitList(it)
Log.d("Doklad", dokladAdapter.currentList.toString())
}
}
}
fun openActivity(view: View){
val intent = Intent(this,PolozkaActivity::class.java )
startActivity(intent)
}
}
这是 ViewModel
@HiltViewModel
class SkladViewModel @Inject constructor(
repository: SybaseRepository
): ViewModel(){
val skladyPolozky = repository.getAllSkladFromPolozka().asLiveData()
val dokladyPolozky = repository.getAllHlavickyToDoklad().asLiveData()
}
这是布局 - 我有两个回收视图。当用户点击 recyclerview A 中的项目时,recyclerview B 中会发生一些事情
<?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">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.02" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.7" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.25" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.75" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.9" />
<TableLayout
android:stretchColumns="1,2"
android:layout_margin="8dp"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/guideline10"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline8">
<TableRow>
<TextView
android:text="SKLAD"
android:textSize="16dp"
android:textStyle="bold"
android:padding="10dp"
android:layout_gravity="center"
android:layout_column="1"/>
<TextView
android:text="REGAL"
android:textSize="16dp"
android:textStyle="bold"
android:padding="10dp"
android:layout_gravity="center"
android:layout_column="1"/>
</TableRow>
<androidx.recyclerview.widget.RecyclerView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recycler_view_sklady"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/sklady_item"
/>
</TableLayout>
<TableLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:stretchColumns="1,2,3,4,5"
app:layout_constraintBottom_toTopOf="@+id/guideline11"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline10"
>
<TableRow>
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="U"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="DOKL"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="ODB"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="ORG"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:layout_gravity="center"
android:padding="10dp"
android:text="DATUM"
android:textSize="16dp"
android:textStyle="bold" />
</TableRow>
<androidx.recyclerview.widget.RecyclerView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recycler_view_doklady"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/doklady_item"/>
</TableLayout>
<Button
android:id="@+id/bt_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:text="Zpět"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline12" />
<Button
android:id="@+id/bt_vybrat_doklad"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:text="Vybrat doklad"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline12" />
<TextView
android:id="@+id/textView2"
android:layout_width="209dp"
android:layout_height="50dp"
android:layout_marginStart="24dp"
android:layout_marginTop="16dp"
android:text="TextView"
app:layout_constraintBottom_toTopOf="@+id/guideline12"
app:layout_constraintEnd_toStartOf="@+id/guideline9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline11" />
</androidx.constraintlayout.widget.ConstraintLayout>
How is it possible to ...
你有一个 ViewModel,它公开了两个可观察的 liveData 和你的 RecyclerViews 需要的列表(两个适配器,两个列表)。
决定列表 A 的项目 1 被点击并因此列表 B 的项目 N 必须更改其背景的逻辑绝对在 回收站视图的范围之外、适配器、Activity,甚至可能是 ViewModel。
最终,当发生数据突变时(您点击了项目 1),您会收到此事件,对其采取行动(又名:将其发送到 Viewmodel -> Repository ->转换数据 -> 使用变异数据发布新列表。
最终,您的 ViewModel 将从存储库接收新数据,并将更新您的 activity 正在观察的 LiveData,这将导致适配器提交新数据,您的DiffUtils 将启动,导致 Adapter 重新绑定修改后的视图。
更新
根据您链接的 question/answer 和您的评论,我认为这值得进一步评论。
此人说:“处理适配器上的点击或使用界面都不是一个好主意”,然后继续“处理”点击,和 使用了一个匿名函数(所以它可能是一个用于测试目的的接口,但它却使它成为一个“高阶函数”)。
这和我描述的原理完全一样,只是接口更容易理解。
想想这样的责任:
ViewHolder:它对数据、回收器视图、适配器等一无所知。但它可以直接访问您的列表中的每个“row/column”。它拥有视图,并且可以根据它提供的数据来操纵它们,并告诉它与所需的视图一起“保存”。它不创建视图(它被告知)但它有它们。关于点击,所有这一切都可以做,要么公开一个视图(这样一个点击监听器可以由外部的人设置)或者简单地委托它。
适配器:除了它们的类型(如果使用)以及如何创建 viewHolders 和“绑定”它们之外,它对视图一无所知。所以它介于两者之间,但它确实可以访问提供给它的数据源(您提供的列表)并且它确实可以访问它创建的每个“视图持有者”;它或多或少知道屏幕上的内容,并且可以将位置映射到数据。
RecyclerView/Fragment/ViewModel:他们不知道适配器内部发生了什么(他们也不应该知道),但他们主要对点击(或事件)发生的时间感兴趣,因此他们大概可以对此做些什么。
基于所有这些,让我们看看
- Adapter 的构造函数修改为接收一个函数:
(private val onSelect: (YourDataType?) -> Unit)
我通常定义一个接口:
interface SomethingClickListener {
fun onSomethingICaredForHappened(something: Something)
}
并将其传递给我的适配器,但思路是一样的;我更喜欢接口,因为它更容易使用具体类型的依赖注入(并且更容易测试),但我相信这只是个人偏好。
class YourAdapter(private val clickListener: SomethingClickListener)
- adapter内部也是一样的原理。您需要在您希望被点击的视图上设置实际的点击侦听器(或者如果您希望整个“行”都可点击,则设置整个 itemView)。
通过简单地使用点击侦听器的匿名实现并捕获发送到绑定方法的值(这很好),您可以(或想在其中做更多的事情)来获得链接的答案。因此,您可以使用另一个界面或那样做,本质上,想法是相同的,您 沿 传递点击事件。
binding.root.setOnClickListener {
onSelect(yourDataType)
}
所以它将 dataType
直接传递给 onSelect
(这是提供给适配器的函数)。在这个阶段,其中唯一的逻辑是您附加与被点击的 viewBinding 关联的“数据”,这是 adapter/viewholder 可以 并且应该 供应。
在这个 onSelect
之后发生的事情是你的 fragment/activity 收到这个,然后你应该调用你的 ViewModel 说:
viewModel.thisThingWasClicked(theThingYouReceived)
你明白了......
我有一段时间没有更新它了(我想我是 3 年前在 Java 中最初写的,然后我天真地将它转换为 Kt)除了更新库并确保它仍然可以编译,但是您可以看到“双接口方法”(有点老派,现在可以通过 Kotlin 获得高阶函数),但仍然是相同的方法。
看看这个项目(特别是 adapter。
注意它接受 ThingClickListener
,但在内部使用 ToggleListener
在 ViewHolder 和 Adapter 之间进行对话。
最后,这可以简化为少用一个界面。
我希望这能澄清我的想法。 请注意,ViewHolder 和 Adapter 除了处理 Click 侦听器和绑定正确的数据之外没有任何责任。