Entonces, finalmente llegué a la culminación de mi idea con una biblioteca que incluye la lógica para seleccionar elementos de una lista en un adaptador. Después de una solución independiente de la plataforma y una biblioteca basada en LiveData , escribí algo para ayudarlo a vincular rápida y fácilmente todo esto a un adaptador para reducir el código general.
Interfaz SelectingListAdapter
Comencemos con una sencilla interfaz SelectingListAdapter que agregué para un adaptador con una lista lineal regular. En mi experiencia, entre el 90 y el 95% de los adaptadores se venden de esta forma.
interface SelectingListAdapter<T> {
fun setListItems(items: ArrayList<T>)
}
Nada complicado, solo actualizando la lista de elementos. Y, en mi opinión, no será difícil agregar esta interfaz a la lista de las implementadas en su adaptador. ¿Para qué? Para poder utilizar ambos métodos de extensión, que mencionaré a continuación:
fun <T> SelectingListAdapter<T>.observeItemsChange(lifecycleOwner: LifecycleOwner,
liveDataSource: LiveDataSource<T>) {
liveDataSource.allItems.observe(lifecycleOwner, { items -> setListItems(items) })
}
El método se observeItemsChange
suscribe a cambios en la lista de elementos en LiveDataSource
.
fun RecyclerView.Adapter<*>.observeSelectionChange(lifecycleOwner: LifecycleOwner,
liveDataSource: LiveDataSource<*>) {
liveDataSource.observeSelectionChange(lifecycleOwner) { position, _ ->
notifyItemChanged(position)
}
}
El método observeSelectionChange
ya se suscribe a cambios en la selección de elementos. Aquí solo hay una notificación de que el elemento debe actualizarse. A continuación se describirá la verificación de si este elemento ya está seleccionado.
fun <T, TAdapter> TAdapter.observeAllChanges(lifecycleOwner: LifecycleOwner,
liveDataSource: LiveDataSource<T>)
where TAdapter : RecyclerView.Adapter<*>,
TAdapter : SelectingListAdapter<T> {
observeSelectionChange(lifecycleOwner, liveDataSource)
observeItemsChange(lifecycleOwner, liveDataSource)
}
Bueno, si desea llamar a ambos métodos a la vez, hay observeAllChanges
uno que lo hará en una línea.
BaseSelectingListAdapter (clase)
, 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
'.
:
Enlaces en 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'