RecyclerView 子控件点击事件的封装与使用
前言
在版本开发的过程中,遇到了需要点击RecyclerView itemView中子控件的需求,但询问了小伙伴之后发现,既不能直接在onBind方法中直接setOnClickListener,也没有其他方法可以直接设置点击事件,只能通过回调实现,稍嫌麻烦,特别是遇到点击事件埋点时,需要传递很多参数。所以萌发了对RecyclerView子控件点击封装的想法,把点击事件抛到UI层,而不需要关心内部做了什么逻辑。
图例(子控件指椭圆所画控件):
思路
对需要设置点击事件的子控件进行保存,统一设置回调
- 需要设置点击事件的View集合
//需要设置点击事件的空间id集合
private val clickChildViewIds = linkedSetOf<Int>()
- 添加需要点击事件的View
fun addOnChildClickListener(@IdRes vararg viewIds: Int) {
viewIds.forEach {
clickChildViewIds.add(it)
}
}
- 点击事件回调
//点击事件回调,参数有holder, position,需要点击的view
typealias OnItemChildClickListener = (holder: BaseHolder, position: Int, view: View) -> Unit
- 点击事件回调赋值
fun setOnItemChildClickListener(onClickListener: OnItemChildClickListener) {
onItemClickListener = onClickListener
}
- 在onCreateViewHolder中间进行点击事件的设置
onItemClickListener?.let { listener ->
for (id in clickChildViewids) {
val childView: View = holder.itemView.findViewById(id) ?: continue
if (childView.isClickable) childView.isClickable = true
childView.setOnClickListener {
val position = holder.adapterPosition
if (position == RecyclerView.NO_POSITION) {
return@setOnClickListener
}
listener.invoke(holder, position, childView)
}
}
}
具体使用
使用的时候很简单,在UI层注册ViewId之后,就可以设置点击事件了
//注册需要点击事件的View
adapter.addOnChildClickViewIds(R.id.tv_name)
//设置点击事件的监听
adapter.setOnItemChildClickListener { holder, position, view ->
when (view.id) {
R.id.tv_name -> {
val name = adapter.items[position].name
Toast.makeText(this, name + position, Toast.LENGTH_SHORT).show()
}
}
}
优点
- 可以避免繁杂的参数传递
- 新增或减少控件点击事件,只需修改注册id即可。
- 解耦adapter中的逻辑。