Created
April 2, 2020 09:30
-
-
Save tommybuonomo/05c32ff7cf8591c49c5ade2da385058f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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