Skip to content

Instantly share code, notes, and snippets.

@tommybuonomo
Created April 2, 2020 09:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tommybuonomo/05c32ff7cf8591c49c5ade2da385058f to your computer and use it in GitHub Desktop.
Save tommybuonomo/05c32ff7cf8591c49c5ade2da385058f to your computer and use it in GitHub Desktop.
package com.lydia.custom.recycler
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import java.lang.reflect.ParameterizedType
/**
* WARNING !
*
* Please annotate all the view holder used on children of this class with [androidx.annotation.Keep]
* See [com.lydia.adapter.RecipientListAdapter.ContactViewHolder]
*
*
*/
abstract class RecyclerMultipleAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
val onClickListeners: HashMap<Class<*>, OnItemClickListener<*>> = HashMap()
val onLongClickListeners: HashMap<Class<*>, OnLongItemClickListener<*>> = HashMap()
@Suppress("UNCHECKED_CAST")
abstract class ViewTypeBinder<Entity, VH : RecyclerView.ViewHolder>(val layoutId: Int) {
abstract fun onBindViewType(entity: Entity, holder: VH)
internal fun bindViewType(entity: Any, holder: RecyclerView.ViewHolder) {
onBindViewType(entity as Entity, holder as VH)
}
internal val entityClazz = (this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<Entity>
internal val holderClazz = (this.javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[1] as Class<VH>
}
protected val items = ArrayList<Any>()
abstract val typeBinders: List<ViewTypeBinder<*, *>>
protected inline fun <Entity, VH : RecyclerView.ViewHolder> binder(layoutId: Int, crossinline onBindType: (Entity, VH) -> Unit): ViewTypeBinder<Entity, VH> {
return object : ViewTypeBinder<Entity, VH>(layoutId) {
override fun onBindViewType(entity: Entity, holder: VH) {
onBindType.invoke(entity, holder)
}
}
}
@Suppress("UNCHECKED_CAST")
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val entity = items[position]
val typeBinderIndex = getItemViewType(position)
check(typeBinderIndex != -1) { "A type binder was not found at position $position" }
val typeBinder = typeBinders[typeBinderIndex]
typeBinder.bindViewType(entity, holder)
onClickListeners[typeBinder.entityClazz]?.let {
holder.itemView.setOnClickListener {
(onClickListeners[typeBinder.entityClazz] as OnItemClickListener<Any>?)?.onItemClick(entity)
}
}
onLongClickListeners[typeBinder.entityClazz]?.let {
holder.itemView.setOnLongClickListener {
(onLongClickListeners[typeBinder.entityClazz] as OnLongItemClickListener<Any>?)?.onLongItemClick(entity)
true
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val binder = typeBinders[viewType]
if (binder.holderClazz == RecyclerView.ViewHolder::class.java) {
return object : RecyclerView.ViewHolder(LayoutInflater.from(parent.context).inflate(binder.layoutId, parent, false)) {}
}
return binder.holderClazz.declaredConstructors[0].newInstance(LayoutInflater.from(parent.context).inflate(binder.layoutId, parent, false)) as RecyclerView.ViewHolder
}
override fun getItemCount() = items.size
open fun setItems(items: List<Any>) {
this.items.clear()
this.items.addAll(items)
notifyDataSetChanged()
}
fun addItems(items: List<Any>) {
this.items.addAll(items)
notifyDataSetChanged()
}
override fun getItemViewType(position: Int): Int {
return typeBinders.indexOfFirst { it.entityClazz == items[position].javaClass }
}
inline fun <reified Entity> addOnClickListener(crossinline listener: (Entity) -> Unit) {
onClickListeners[Entity::class.java] = object : OnItemClickListener<Entity> {
override fun onItemClick(entity: Entity) {
listener.invoke(entity)
}
}
}
inline fun <reified Entity> addOnLongClickListener(crossinline listener: (Entity) -> Boolean) {
onLongClickListeners[Entity::class.java] = object : OnLongItemClickListener<Entity> {
override fun onLongItemClick(entity: Entity): Boolean {
return listener.invoke(entity)
}
}
}
interface OnItemClickListener<Entity> {
fun onItemClick(entity: Entity)
}
interface OnLongItemClickListener<Entity> {
fun onLongItemClick(entity: Entity): Boolean
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment