Say goodbye to repeated, redundant custom Adapters , Make the developer's focus on the data, beacuse data-driven UI
PaoNet : https://github.com/ditclear/paonet
implementation 'com.ditclear:bindinglistadapter:1.0.1'
// if you use androidx
implementation 'com.ditclear:bindinglistadapterx:1.0.0'
creating a single-type RecyclerView.Adapter with only a simple 3 step
- Create a
list-item.xml
file in databinding form for Item
<?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="item"
type="String"/>
<variable
name="presenter"
type="io.ditclear.bindingadapter.ItemClickPresenter"/>
</data>
<TextView
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:onClick="@{(v)->presenter.onItemClick(v,item)}"
android:gravity="center"
android:text="@{item}"/>
</layout>
-
Create our
dataSource
andSingleTypeAdapter
inActivity/Fragment
fileval dataSource=ObservableArrayList<T>() //typically in the ViewModel layer val mAdapter by lazy { SingleTypeAdapter<T>(this, R.layout.list_item, dataSource) .apply{ itemPresenter=this@currentActity } }
-
set
adapter
forrecyclerView
recyclerView.apply{ adapter = mAdapter layoutManager = LinearLayoutManager(context) }
Over, you're done. Then just change the data source
//add item
dataSource.add(item)
//remove item
dataSource.remove(item) // or dataSource.removeAt(indexOfItem)
//setNewList
dataSource.clear()
dataSource.addAll(newList)
//batch remove
dataSouce.removeRange(startIndex ,offset) //kotin extension
//and so on
The Android DataBinding framework provides the ObservableArrayList
class, which provides several callbacks corresponding to RecyclerView.Adapter.
dataSource.addOnListChangedCallback(object : ObservableList.OnListChangedCallback<ObservableList<T>>() {
override fun onChanged(contributorViewModels: ObservableList<T>) {
notifyDataSetChanged()
}
override fun onItemRangeChanged(contributorViewModels: ObservableList<T>, i: Int, i1: Int) {
notifyItemRangeChanged(i, i1)
}
override fun onItemRangeInserted(contributorViewModels: ObservableList<T>, i: Int, i1: Int) {
notifyItemRangeInserted(i, i1)
}
override fun onItemRangeMoved(contributorViewModels: ObservableList<T>, i: Int, i1: Int, i2: Int) {
notifyItemMoved(i, i1)
}
override fun onItemRangeRemoved(contributorViewModels: ObservableList<T>, i: Int, i1: Int) {
if (contributorViewModels.isEmpty()) {
notifyDataSetChanged()
} else {
notifyItemRangeRemoved(i,i1)
}
}
})
Provides SingleTypeAdapter and MultiTypeAdapter
- SingleTypeAdapter
val dataSource=ObservableArrayList<T>()
val mAdapter by lazy {
SingleTypeAdapter<T>(this, R.layout.list_item, dataSource)
}
- MultiTypeAdapter
val dataSource=ObservableArrayList<Any>()
val mAdapter by lazy {
MultiTypeAdapter(this, dataSource, object : MultiTypeAdapter.MultiViewTyper {
override fun getViewType(item: Any): Int =
when(item){ //return Item View type
is ItemWrapper -> item.type
is String -> ItemType.TYPE_5
else -> throw Resources.NotFoundException("${item::class} has not found it's ViewType")
}
}).apply {
addViewTypeToLayoutMap(ItemType.TYPE_0, R.layout.multi_type_0)
addViewTypeToLayoutMap(ItemType.TYPE_1, R.layout.multi_type_1)
addViewTypeToLayoutMap(ItemType.TYPE_2, R.layout.multi_type_2)
addViewTypeToLayoutMap(ItemType.TYPE_3, R.layout.multi_type_3)
addViewTypeToLayoutMap(ItemType.TYPE_4, R.layout.multi_type_4)
addViewTypeToLayoutMap(ItemType.TYPE_5, R.layout.multi_type_5)
}
}
ItemClickPresenter is provided to handle click events
//single type : According to the viewId to distinguish
override fun onItemClick(v: View, item: String) {
Toast.makeText(this,item,Toast.LENGTH_SHORT).show()
}
//multi type : According to the viewId or item's type to distinguish
override fun onItemClick(v: View, item: Any) {
when(item){
is ItemWrapper -> Toast.makeText(this, item.bean, Toast.LENGTH_SHORT).show()
is String -> Toast.makeText(this, item.split("").reversed().joinToString(""), Toast.LENGTH_SHORT).show()
}
}
in list_item.xml
,We need to bind the click event
<?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="item"
type="String"/>
<variable
name="presenter"
type="io.ditclear.bindingadapter.ItemClickPresenter"/>
</data>
<TextView
android:onClick="@{(v)->presenter.onItemClick(v,item)}"
android:text="@{item}"/>
</layout>
If the above cannot meet the requirements, additional settings can be made by setting ItemDecorator
override fun decorator(holder: BindingViewHolder<ViewDataBinding>, position: Int, viewType: Int) {
//do sth..
}
Similar to onBindViewHolder
method