|
| 1 | +package com.smarttoolfactory.tutorial3_1transitions.adapter |
| 2 | + |
| 3 | +import android.view.ViewGroup |
| 4 | +import androidx.recyclerview.widget.ListAdapter |
| 5 | +import androidx.recyclerview.widget.RecyclerView.ViewHolder |
| 6 | +import com.smarttoolfactory.tutorial3_1transitions.adapter.viewholder.ItemClazz |
| 7 | +import com.smarttoolfactory.tutorial3_1transitions.adapter.viewholder.MappableItemBinder |
| 8 | + |
| 9 | +/** |
| 10 | + * RecyclerView adapter for setting list with different layouts using [MappableItemViewBinder]. |
| 11 | + * |
| 12 | + * Takes [Map] of model class [ItemClazz] and [ViewHolder] and transforms that |
| 13 | + * map to [viewTypeToBinders] with keys that point to layouts |
| 14 | + * returned from [MappableItemViewBinder.getItemLayoutResource]. |
| 15 | + * |
| 16 | + * Mapping happens between Model::class.java <-> ViewBinder |
| 17 | + * and between R.layout.RES <-> ViewBinder to glue from model class to layout getItemType |
| 18 | + * checks class of data which is send to this adapter with [ListAdapter.submitList]. |
| 19 | + * |
| 20 | + * * For instance, if array of items has three types such as |
| 21 | + * Model1, Model2, and Model3, then there should be |
| 22 | + * ViewBinder1, ViewBinder2, and ViewBinder each with it's own unique layout resource. |
| 23 | + * |
| 24 | + * * Whenever a type of model in array is returned based on position, |
| 25 | + * ViewBinder that is mapped with that model class is returned from map. |
| 26 | + * |
| 27 | + */ |
| 28 | +class MultipleViewBinderListAdapter( |
| 29 | + private val viewBinders: Map<ItemClazz, MappableItemBinder>, |
| 30 | + stateRestorationPolicy: StateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY |
| 31 | +) : ListAdapter<Any, ViewHolder>(ItemDiffCallback(viewBinders)) { |
| 32 | + |
| 33 | + init { |
| 34 | + this.stateRestorationPolicy = stateRestorationPolicy |
| 35 | + } |
| 36 | + |
| 37 | + /** |
| 38 | + * Map of layout resource keys to ViewBinder values |
| 39 | + */ |
| 40 | + private val viewTypeToBinders = viewBinders.mapKeys { it.value.getItemLayoutResource() } |
| 41 | + |
| 42 | + private fun getViewBinder(viewType: Int): MappableItemBinder = |
| 43 | + viewTypeToBinders.getValue(viewType) |
| 44 | + |
| 45 | + /** |
| 46 | + * Map from data clazz to layout type by returning RecyclerView's |
| 47 | + * item view type as layout resource id. [getItem] returns the [Class] that ViewBinder |
| 48 | + * constructor parameter and data type shares. |
| 49 | + */ |
| 50 | + override fun getItemViewType(position: Int): Int = |
| 51 | + viewBinders.getValue(super.getItem(position).javaClass).getItemLayoutResource() |
| 52 | + |
| 53 | + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { |
| 54 | + return getViewBinder(viewType).createViewHolder(parent) |
| 55 | + } |
| 56 | + |
| 57 | + /** |
| 58 | + * Get ViewBinder in specific position by calling [getItemViewType] with position, |
| 59 | + * and bind data that is already is coupled with data type |
| 60 | + */ |
| 61 | + override fun onBindViewHolder(holder: ViewHolder, position: Int) { |
| 62 | + return getViewBinder(getItemViewType(position)).bindViewHolder(getItem(position), holder) |
| 63 | + } |
| 64 | + |
| 65 | + override fun onViewRecycled(holder: ViewHolder) { |
| 66 | + getViewBinder(holder.itemViewType).onViewRecycled(holder) |
| 67 | + super.onViewRecycled(holder) |
| 68 | + } |
| 69 | + |
| 70 | + override fun onViewDetachedFromWindow(holder: ViewHolder) { |
| 71 | + getViewBinder(holder.itemViewType).onViewDetachedFromWindow(holder) |
| 72 | + super.onViewDetachedFromWindow(holder) |
| 73 | + } |
| 74 | +} |
0 commit comments