如何使用 Kotlin 在 RecyclerView Adapter 中实现 onClick 并进行数据绑定
Posted
技术标签:
【中文标题】如何使用 Kotlin 在 RecyclerView Adapter 中实现 onClick 并进行数据绑定【英文标题】:How to implement onClick in RecyclerView Adapter with databinding using Kotlin 【发布时间】:2021-07-07 07:40:38 【问题描述】:我使用数据绑定创建了一个 RecyclerView 适配器,我正在尝试处理此适配器内的 Click 事件,但我不知道具体如何。我找到了不同的主题,但还不能解决我的问题。谢谢! 我应该在哪里(在 Adapter 类中)实现 onClick 函数?
适配器类
class RemovableContactsAdapter(val viewModel: GroupDetailsViewModel,val callback:GroupContactsCallback) : RecyclerView.Adapter<RemovableContactsViewHolder>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RemovableContactsViewHolder
val binding: ViewDataBinding =
DataBindingUtil.inflate(LayoutInflater.from(parent.context), viewType, parent, false)
return RemovableContactsViewHolder(binding)
override fun onBindViewHolder(holder: RemovableContactsViewHolder, position: Int)
holder.bind(viewModel, callback, position)
override fun getItemCount(): Int
return viewModel.currentGroup.value?.contacts?.size ?: 0
override fun getItemViewType(position: Int): Int
return R.layout.removable_contact_layout
class RemovableContactsViewHolder(val binding: ViewDataBinding) :
RecyclerView.ViewHolder(binding.root)
fun bind(viewModel: GroupDetailsViewModel, callback: GroupContactsCallback, position: Int)
binding.root.selected_contact_iv.apply
visibility = if (viewModel.currentGroup.value?.contacts!![position].selected)
View.VISIBLE
else
View.GONE
binding.setVariable(BR.contact, viewModel.currentGroup.value?.contacts?.get(position))
binding.setVariable(BR.callback, callback)
binding.executePendingBindings()
Fragment 类中的回调接口:
interface GroupContactsCallback
fun selectContact(contact: ContactModel)
编辑
我更新了 RemovableContactsViewHolder 中的绑定函数,但仍然无法正常工作。
class RemovableContactsViewHolder(val binding: ViewDataBinding) :
RecyclerView.ViewHolder(binding.root)
fun bind(viewModel: GroupDetailsViewModel, callback: GroupContactsCallback, position: Int)
itemView.setOnClickListener
viewModel.currentGroup.value?.contacts?.get(position)!!.selected = !viewModel.currentGroup.value?.contacts?.get(position)!!.selected
callback.selectContact(viewModel.currentGroup.value?.contacts?.get(position)!!)
binding.root.selected_contact_iv.apply
visibility = if (viewModel.currentGroup.value?.contacts!![position].selected)
View.VISIBLE
else
View.GONE
binding.setVariable(BR.contact, viewModel.currentGroup.value?.contacts?.get(position))
binding.setVariable(BR.callback, callback)
binding.executePendingBindings()
【问题讨论】:
似乎很常见的问题,看看这个medium.com/android-gate/… 我阅读了这篇文章并在 ViewHolder 类的绑定函数中添加了 onClickListener,但仍然无法正常工作。我更新了问题,请看一下。谢谢! 【参考方案1】:在适配器内部处理点击不是一个好习惯。并且不要仅仅为此使用界面。改用这个。
class YourRecyclerViewAdapter(private val onSelect: (YourDataType?) -> Unit) : RecyclerView.Adapter<YourRecyclerViewAdapter.YourViewHolder>()
override fun onBindViewHolder(holder: YourViewHolder, position: Int)
holder.bind(getItem(position), onSelect)
class ViewHolder(private val binding: YourViewBinding) : RecyclerView.ViewHolder(binding.root)
fun bind(yourDataType: YourDataType?, onSelect: (YourDataType?) -> Unit)
// bind your view here
binding.root.setOnClickListener
onSelect(yourDataType)
在您的片段/活动中
// Set this adapter to your recycler view
val adapter = YourRecyclerViewAdapter yourDataType->
// Handle click here
【讨论】:
好答案,但我还要解释为什么在适配器内处理点击是不好的做法 我有那个回调作为适配器的参数,使用它不是更好吗?谢谢 嗯,它打破了“关注点分离”的概念。适配器关注的只是充当我们数据的桥梁,而不是处理点击的recyclerview。将其传递回片段/活动可以恢复它。其次,使用回调可能会导致内存泄漏,因为它会引用片段/活动。 @Razvan22 回调并不理想。我们显然可以使用它,但可能会发生内存泄漏。这也是处理点击的一种非常干净的方式。【参考方案2】:override fun onBindViewHolder(holder: RemovableContactsViewHolder, position: Int)
holder.bind(viewModel, callback, position)
holder.binding.your_view_like_button.setOnClickListener
// do something
例如
class AppointTimeSloatAdapter(
private var mOptionList: List<String>,
var context: Context,
var appointmentDate: String,
) : RecyclerView.Adapter<AppointTimeSloatAdapter.ViewHolder>()
private var checkedRadioButton: CompoundButton? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder
val viewProductCategoryBinding: AdapterAppointmentTimeSloteBinding =
AdapterAppointmentTimeSloteBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return ViewHolder(viewProductCategoryBinding)
override fun onBindViewHolder(holder: ViewHolder, position: Int)
val option = getItem(position)
holder.binding.radioBtn.text = option.toString()
holder.binding.radioBtn.setOnCheckedChangeListener(checkedChangeListener)
if (holder.binding.radioBtn.isChecked) checkedRadioButton = holder.binding.radioBtn
holder.binding.radioBtn.setOnClickListener
var intent = Intent(context, NewAppointmentActivity::class.java)
intent.putExtra("time",holder.binding.radioBtn.text.toString())
intent.putExtra("appointmentDate", appointmentDate)
context.startActivity(intent)
private val checkedChangeListener =
CompoundButton.OnCheckedChangeListener compoundButton, isChecked ->
checkedRadioButton?.apply setChecked(!isChecked)
checkedRadioButton = compoundButton.apply setChecked(isChecked)
fun updateList(list: ArrayList<String>)
mOptionList = list
notifyDataSetChanged()
private fun getItem(index: Int): String
return mOptionList[index]
override fun getItemCount(): Int
return mOptionList.size
inner class ViewHolder(val binding: AdapterAppointmentTimeSloteBinding) :
RecyclerView.ViewHolder(binding.root), View.OnClickListener
override fun onClick(v: View?)
////
【讨论】:
【参考方案3】:应用以下方法。
在您的适配器类中
class RemovableContactsAdapter(val viewModel: GroupDetailsViewModel,val callback:GroupContactsCallback) : RecyclerView.Adapter<RemovableContactsViewHolder>()
private var onClickListener: OnClickListener?=null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RemovableContactsViewHolder
val binding: ViewDataBinding =
DataBindingUtil.inflate(LayoutInflater.from(parent.context), viewType, parent, false)
return RemovableContactsViewHolder(binding)
override fun onBindViewHolder(holder: RemovableContactsViewHolder, position: Int)
holder.bind(viewModel, callback, position)
holder.itemView.setOnClickListener
if(onClickListener!=null)
onClickListener!!.onClick(position)
override fun getItemCount(): Int
return viewModel.currentGroup.value?.contacts?.size ?: 0
override fun getItemViewType(position: Int): Int
return R.layout.removable_contact_layout
class RemovableContactsViewHolder(val binding: ViewDataBinding) :
RecyclerView.ViewHolder(binding.root)
fun bind(viewModel: GroupDetailsViewModel, callback: GroupContactsCallback, position: Int)
binding.root.selected_contact_iv.apply
visibility = if (viewModel.currentGroup.value?.contacts!![position].selected)
View.VISIBLE
else
View.GONE
binding.setVariable(BR.contact, viewModel.currentGroup.value?.contacts?.get(position))
binding.setVariable(BR.callback, callback)
binding.executePendingBindings()
fun setOnClickListener(onClickListener: OnClickListener)
this.onClickListener=onClickListener
interface OnClickListener
fun onClick(position: Int)
在你的 Activity/Fragment 类中创建一个名为 adapter 的对象,然后
val adapter=RemovableContactsAdapter(viewModel,callback)
adapter.setOnClickListener(object :SettingAdapter.OnClickListener
override fun onClick(position: Int)
//position is your clicked view position
)
我已经在我的回答中修改了你的代码,希望问题能得到解决。
【讨论】:
以上是关于如何使用 Kotlin 在 RecyclerView Adapter 中实现 onClick 并进行数据绑定的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Kotlin 中使用 ViewModelProviders
如何在 Kotlin Multiplatform(纯 kotlin)中进行延迟