So, I finally got to the culmination of my idea with a library that includes the logic for selecting items from a list in an adapter. After a platform independent solution and a library based on LiveData , I wrote something to help you quickly and easily link all of this to an adapter to reduce the overall code.
SelectingListAdapter interface
Let's start with a simple SelectingListAdapter interface that I added for an adapter with a regular linear list. In my experience, somewhere between 90-95% of adapters are sold in this form.
interface SelectingListAdapter<T> {
fun setListItems(items: ArrayList<T>)
}
Nothing complicated - just updating the list of items. And, in my opinion, it will not be difficult to add this interface to the list of those implemented in your adapter. What for? So that you can use both extension methods, which I will point out next:
fun <T> SelectingListAdapter<T>.observeItemsChange(lifecycleOwner: LifecycleOwner,
liveDataSource: LiveDataSource<T>) {
liveDataSource.allItems.observe(lifecycleOwner, { items -> setListItems(items) })
}
The method observeItemsChange
subscribes to changes to the list of items in LiveDataSource
.
fun RecyclerView.Adapter<*>.observeSelectionChange(lifecycleOwner: LifecycleOwner,
liveDataSource: LiveDataSource<*>) {
liveDataSource.observeSelectionChange(lifecycleOwner) { position, _ ->
notifyItemChanged(position)
}
}
The method observeSelectionChange
already subscribes to changes in the selection of items. Here there is only a notification that the element needs to be updated. Checking whether this item is already selected will be described below.
fun <T, TAdapter> TAdapter.observeAllChanges(lifecycleOwner: LifecycleOwner,
liveDataSource: LiveDataSource<T>)
where TAdapter : RecyclerView.Adapter<*>,
TAdapter : SelectingListAdapter<T> {
observeSelectionChange(lifecycleOwner, liveDataSource)
observeItemsChange(lifecycleOwner, liveDataSource)
}
Well, if you want to call both methods at once, there is observeAllChanges
one that will do it in one line.
BaseSelectingListAdapter Class
, LiveDataSource
, . , :
abstract class BaseSelectingListAdapter<T, VH: BaseSelectingListHolder<T>>
: RecyclerView.Adapter<VH>(), SelectingListAdapter<T> {
var callback: SelectingListAdapterCallback? = null
...
}
abstract class BaseSelectingListHolder<T>(itemView: View) : RecyclerView.ViewHolder(itemView) {
abstract fun bindItem(item: T, isSelected: Boolean, onClick: (() -> Unit)?)
}
, SelectingListAdapterCallback
.
interface SelectingListAdapterCallback {
fun isItemSelected(position: Int): Boolean
fun clickItem(position: Int)
}
, , , .
BaseSelectingListAdapter
, LiveDataSource
.
fun <T> setCallback(liveDataSource: LiveDataSource<T>) {
callback = object : SelectingListAdapterCallback {
override fun isItemSelected(position: Int) =
liveDataSource.isItemSelected(position)
override fun clickItem(position: Int) {
liveDataSource.clickPosition(position)
}
}
}
BaseSelectingListAdapter
— , .
fun fullyInitialize(lifecycleOwner: LifecycleOwner,
liveDataSource: LiveDataSource<T>) {
observeAllChanges(lifecycleOwner, liveDataSource)
setCallback(liveDataSource)
}
fullyInitialize
, . . , , .
onCreateViewHolder
bindItem
. -, boilerplate .
class MyAdapter : BaseSelectingListAdapter<User, MyHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
MyHolder(...)//create your holder view
}
class MyHolder(itemView: View) : BaseSelectingListHolder<User>(itemView) {
override fun bindItem(item: User, isSelected: Boolean, onClick: (() -> Unit)?) {
//bind your data
}
}
, . - , , :
- .
- ( , ),
SelectionManager
'.
:
Links in Gradle:
implementation 'ru.ircover.selectionmanager:core:1.1.0'
implementation 'ru.ircover.selectionmanager:livesource:1.0.1'
implementation 'ru.ircover.selectionmanager:selectingadapter:1.0.0'