在项目开发中,总离不开列表,说到列表,就会有无穷无尽的 Adapter 需要你去实现。从而出现了很多优秀的 adapter 库。 不过很多库功能都很全面了,有很多个类,很多功能,但是实际上只用其中的一两个我感觉是很多人的现状。所以自己实现一个是一个不错的 选择,特别是用在一些不是很复杂的列表时。
先祭出使用效果,激发一下你继续阅读的激情:
//单类型列表
recycleView.setup<NumberInfo> {
dataSource(initData())
adapter {
addItem(R.layout.layout_item) {
isForViewType { it != null }
bindViewHolder { data, _, _ ->
setText(R.id.number, data?.number.toString())
}
}
}
}
//多类型列表
recycleView.setup<Any> {
withLayoutManager { LinearLayoutManager(context) }
adapter {
addItem(R.layout.item_setion_header) {
isForViewType { it is SectionHeader }
bindViewHolder { data, _, _ ->
val header = data as SectionHeader
setText(R.id.section_title, header.title)
}
}
addItem(R.layout.item_user) {
isForViewType { it is User }
bindViewHolder { data, _, _ ->
val user = data as User
setText(R.id.name, user.name)
setImageResource(R.id.avatar, user.avatarRes)
//如果你的控件找不到方便赋值的方法,可以通过 findViewById 去查找
val phone = findViewById<TextView>(R.id.phone)
phone.text = user.phone
}
}
}
}
recycleView.submitList(data)
嗯....,感觉还可以,最少的情况下可以把一个列表代码用 10 级行就完成了。
没地址说个蛋,先贴完整代码地址:EfficientAdapter
我把它命名为 EfficientAdapter ,意为高效的意思,事实上它只有 3 个类。
至于如何使用,在地址上已经描述了,所以这篇文章主要是讲一下实现的思路。
对 Adapter 的封装,其实无非就是对 Adapter 里面的几个回调方法进行封装罢了,最常用的方法是先定义填充好一个 ViewHolder 列表,然后在各个回调中获取这些 ViewHolder,然后实现逻辑。
那么其中最操蛋的是哪个回调方法的封装呢?我认为是 getItemViewType。事实上你可以在很多框架中看到让你实现获取 ViewType 的回调方法。
一步一步来,先说 ViewHolder 的封装
在 EfficientAdapter 里面,我把 ViewHolder 的封装写成了 BaseViewHolder:
class BaseViewHolder(parent: ViewGroup, resource: Int) : RecyclerView.ViewHolder(
LayoutInflater.from(parent.context).inflate(resource, parent, false)
)
这就是我的封装,够简单吧。
想什么呢,当然没这么简单,想要在上面使用效果中那样实现 ViewHolder 的具体逻辑,还需要 isForViewType,bindViewHolder 等方法。所以我要定义一个类,去提供这些方法:
abstract class ViewHolderCreator<T> {
abstract fun isForViewType(data: T?, position: Int): Boolean
abstract fun getResourceId(): Int
abstract fun onBindViewHolder(
data: T?,
items: MutableList<T>?,
position: Int,
holder: ViewHolderCreator<T>
)
var itemView: View? = null
fun registerItemView(itemView: View?) {
this.itemView = itemView
}
fun <V : View> findViewById(viewId: Int): V {
checkItemView()
return itemView!!.findViewById(viewId)
}
private fun checkItemView() {
if (itemView == null) {
throw NullPointerException("itemView is null")
}
}
}