仓库地址 https://gitee.com/BigObj/bo-an-poj-common
一、需求及规范
1、需求
RecyclerView 是我们常用的列表控件,直接使用时通常大量代码编写于 Adapter 中,当 item 包含视图类型过多时,Adapter 会臃肿不堪,故需要将各个类型视图单独定义编写。
2、规范
主要定义五个模块:adapter、viewHolder、viewHolderFactory、itemView、model
adapter:及 RecyclerView.Adapter 适配器,用来整合填充数据
viewHolder:及 RecyclerView.ViewHolder 视图固定器,用来实现视图重用
viewHolderFactory:创建 viewHolder,并实现多类型视图设置
itemView:item视图代码编写
model:定义公共model,便于使用
二、代码编写
RecyclerViewAdapter
abstract class RecyclerViewAdapter<M: RecyclerViewModel>(private var context: Context) :
RecyclerView.Adapter<RecyclerViewHolder<M, out ViewDataBinding, out ItemRecyclerView<M, out ViewDataBinding>>>() {
private val dataList: MutableList<M> by lazy {
ArrayList()
}
fun addAllDataList(dataList: List<M>) {
this.dataList.addAll(dataList)
notifyDataSetChanged()
}
fun addAllSpaceArray(sparseArray: SparseArray<ItemSpace>) {
viewHolderFactory.spaceArray.putAll(sparseArray)
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return dataList.size
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerViewHolder<M, out ViewDataBinding, out ItemRecyclerView<M, out ViewDataBinding>> {
return viewHolderFactory.createViewHolder(context, parent, viewType)
}
protected abstract val viewHolderFactory: ViewHolderFactory<M>
fun getItem(position: Int): M {
return dataList[position]
}
override fun onBindViewHolder(
holder: RecyclerViewHolder<M, out ViewDataBinding, out ItemRecyclerView<M, out ViewDataBinding>>,
position: Int
) {
holder.itemRecyclerView.dataBinding(dataList[position], position)
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
recyclerView.addItemDecoration(RecyclerItemDecoration(viewHolderFactory.spaceArray))
}
}
RecyclerViewHolder
class RecyclerViewHolder<M: RecyclerViewModel, VDB: ViewDataBinding, V: ItemRecyclerView<M, VDB>>(var itemRecyclerView: V)
: RecyclerView.ViewHolder(itemRecyclerView.rootView)
ViewHolderFactory
abstract class ViewHolderFactory<M: RecyclerViewModel> {
abstract fun createViewHolder(context: Context, parent: ViewGroup, viewType: Int):
RecyclerViewHolder<M, out ViewDataBinding, out ItemRecyclerView<M, out ViewDataBinding>>
}
ItemRecyclerView
abstract class ItemRecyclerView<M: RecyclerViewModel, VDB: ViewDataBinding>(context: Context, parent: ViewGroup) {
val binding: VDB by lazy {
DataBindingUtil.inflate(LayoutInflater.from(context), getItemLayoutId(), parent, false) as VDB
}
val viewHolder: RecyclerViewHolder<M, VDB, out ItemRecyclerView<M, VDB>> by lazy {
RecyclerViewHolder(this)
}
val rootView: View by lazy {
binding.root
}
abstract fun dataBinding(m: M, position: Int)
abstract fun getItemLayoutId(): Int
}
RecyclerViewModel
abstract class RecyclerViewModel
三、使用
DemoViewHolderFactory
class DemoViewHolderFactory: ViewHolderFactory<DemoModel>() {
override fun createViewHolder(
context: Context,
parent: ViewGroup,
viewType: Int
): RecyclerViewHolder<DemoModel, *, *> {
return DemoItemView(context, parent).viewHolder
}
}
DemoItemView
class DemoItemView(context: Context, parent: ViewGroup): ItemRecyclerView<DemoModel, ItemDemoBinding>(context, parent) {
override fun dataBinding(m: DemoModel, position: Int) {
binding.demo = m
}
override fun getItemLayoutId(): Int {
return R.layout.item_demo
}
}
DemoModel
class DemoModel: RecyclerViewModel() {
var title: String? = null
var content: String? = null
}
DemoAdapter
class DemoAdapter(context: Context): RecyclerViewAdapter<DemoModel>(context) {
override fun createViewHolderFactory(): ViewHolderFactory<DemoModel> {
return DemoViewHolderFactory()
}
}
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.demoListView.layoutManager = LinearLayoutManager(this)
val adapter = DemoAdapter(this)
binding.demoListView.adapter = adapter
val dataList = ArrayList<DemoModel>()
for (i in 0..20) {
val data = DemoModel()
data.title = "title $i"
data.content = "content $i"
dataList.add(data)
}
adapter.addAllDataList(dataList)
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/demo_list_View"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
item_demo
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="demo"
type="com.ww7h.bigobj.DemoModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/title"
android:text="@{demo.title}"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:text="@{demo.content}"
app:layout_constraintTop_toBottomOf="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>