概述
在使用MultiTypeAdapter實現RecyclerView多類型顯示的時候,會創建一個ViewHolder和ViewBinder,此時如果要在Activity或者Fragment相應點擊事件的時候,需要在ViewHolder和ViewBinder之間做傳遞。如果一個ViewHolder下有RecyclerView,然后也使用了MultiTypeAdapter,那么這個點擊事件的回調將會是一件相當頭疼的事情。
啟發
在使用LifeCycle
時,發現他只需要當前類實現LifecycleObserver
,然后通過調用addObserver
方法即可實現事件傳遞。由此想到點擊事件是否也可以使用此種形式來實現。
DEMO
效果圖
demo (1).gif
實現
在受到LifeCycle
的啟發下,模仿這寫了幾個類。
- OnItemClick
abstract class OnItemClick {
abstract fun addObserver(onItemClickObserver: OnItemClickObserver)
abstract fun addObserver(list: List<OnItemClickObserver>?)
abstract fun getObserver(): List<OnItemClickObserver>?
abstract fun dispatchObserver(onItemClickObserver: OnItemClickObserver)
abstract fun dispatchObserver(list: List<OnItemClickObserver>?)
abstract fun removeObserver(onItemClickObserver: OnItemClickObserver)
abstract fun removeAll()
}
定義一系列的操作方法,包括添加、移除、傳遞等。
- OnItemClickOwner
interface OnItemClickOwner {
fun getOnItemClick(): OnItemClick
}
一個點擊事件如果在某個類中如果需要做操作,那么需要實現該接口。
- OnItemClickRegistry
class OnItemClickRegistry() : OnItemClick() {
// 省略具體代碼
}
繼承OnItemClick,并實現具體的方法。
- OnItemClickObserver
interface OnItemClickObserver
基本點擊事件Observer
ViewBinder/ViewHolder 改造
- BaseViewHolder
abstract class BaseViewHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView), OnItemClickOwner {
var mT: T? = null
var mContext: Context = itemView.context
abstract fun setData(t: T)
}
- BaseViewHolderWrapper
open class BaseViewHolderWrapper<T>(itemView: View) :
BaseViewHolder<T>(itemView), View.OnClickListener {
private val onItemRegistry = OnItemClickRegistry(this)
override fun setData(@NonNull t: T) {
mT = t
itemView?.setOnClickListener(this)
}
override fun onClick(v: View) {
}
fun <R : OnItemClickObserver> getObserver(clazz: Class<R>): R? {
getOnItemClick().getObserver()?.forEach {
if (clazz.isInstance(it)) {
@Suppress("UNCHECKED_CAST")
return it as R
}
}
return null
}
override fun getOnItemClick(): OnItemClick {
return onItemRegistry
}
}
- BaseViewBinder
abstract class BaseViewBinder<T, R : BaseViewHolderWrapper<T>> : ItemViewBinder<T, R>(), OnItemClickOwner {
private val onItemRegistry = OnItemClickRegistry(this)
override fun getOnItemClick(): OnItemClick {
return onItemRegistry
}
@LayoutRes
private val layoutId: Int
@LayoutRes
abstract fun getLayoutId(): Int
init {
layoutId = this.getLayoutId()
}
fun getItemView(inflater: LayoutInflater, parent: ViewGroup): View {
if (layoutId == 0) {
throw IllegalArgumentException("You must return a layout id.")
}
return inflater.inflate(layoutId, parent, false)
}
override fun onBindViewHolder(holder: R, item: T) {
holder.getOnItemClick().dispatchObserver(getOnItemClick().getObserver())
holder.setData(item)
}
}
這一層,對事件在OnBindViewHolder中做了一次傳遞,通過dispatchObserver方法,將ViewBinder中的事件傳遞到了ViewHolder中。
使用
Observer
interface Observer1 : OnItemClickObserver {
fun onClick1()
}
interface Observer2 : OnItemClickObserver {
fun onClick2()
}
定義兩個點擊事件。
Bean
data class Bean1(var name: String)
class Bean2
創建實體類,和Binder相對應。
ViewHolder
- ViewHolder1
class ViewHolder1(itemView: View) : BaseViewHolderWrapper<Bean1>(itemView) {
private val textView = itemView.findViewById<TextView>(R.id.textView)
override fun setData(t: Bean1) {
super.setData(t)
textView.text = t.name
}
override fun onClick(v: View) {
getObserver(Observer1::class.java)?.onClick1()
}
}
在覆寫setData
方法的時候,一定要調用super。不然事件無法傳遞。
響應事件的回調,只需要調用getObserver
方法,然后傳入對應的Observer,如果有,就直接調用方法。
- ViewHolder2
class ViewHolder2(itemView: View) : BaseViewHolderWrapper<Bean2>(itemView) {
var recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView2)
private val adapter = RecyclerViewAdapter2(mContext)
init {
recyclerView.layoutManager = LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false)
recyclerView.adapter = adapter
adapter.submitList(listOf(
Bean1("第二層"),
Bean1("第二層"),
Bean1("第二層")
))
}
override fun setData(t: Bean2) {
super.setData(t)
adapter.getOnItemClick().dispatchObserver(getOnItemClick().getObserver())
}
override fun onClick(v: View) {
getObserver(Observer2::class.java)?.onClick2()
}
}
adapter傳遞事件,也是通過dispatchObserver方法。
ViewBinder
ViewBinder其實就不需要做什么事情了,比較簡單。
class Binder1 : BaseViewBinder<Bean1, ViewHolder1>() {
override fun getLayoutId(): Int {
return R.layout.item_1
}
override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder1 {
return ViewHolder1(getItemView(inflater, parent))
}
}
class Binder2 : BaseViewBinder<Bean2, ViewHolder2>() {
override fun getLayoutId(): Int {
return R.layout.item_2
}
override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder2 {
return ViewHolder2(getItemView(inflater, parent))
}
}
Activity
- 注冊
val binder1 = Binder1()
val binder2 = Binder2()
multiTypeAdapter.register(Bean1::class.java, binder1)
multiTypeAdapter.register(Bean2::class.java, binder2)
- 添加點擊事件
binder1.getOnItemClick().addObserver(object : Observer1 {
override fun onClick1() {
Toast.makeText(this@MainActivity, "binder1 onClick1", Toast.LENGTH_SHORT).show()
}
})
binder2.getOnItemClick().addObserver(object : Observer1 {
override fun onClick1() {
Toast.makeText(this@MainActivity, "binder2 onClick1", Toast.LENGTH_SHORT).show()
}
})
binder2.getOnItemClick().addObserver(object : Observer2 {
override fun onClick2() {
Toast.makeText(this@MainActivity, "binder2 onClick2", Toast.LENGTH_SHORT).show()
}
})