Last active
January 25, 2017 15:16
-
-
Save heinrisch/9250cad3c61b4fc71913cb94fe053d4d to your computer and use it in GitHub Desktop.
Now it works with animations! Reset the index before calling notifyItemXXX
This file contains hidden or 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 co.leftorright.android.util | |
import android.support.v7.widget.RecyclerView | |
import android.view.View | |
import android.view.ViewGroup | |
/** | |
* Created by henrik on 02/08/16. | |
*/ | |
class ViewHolderWrapper(viewHolder: RecyclerView.ViewHolder) : RecyclerView.ViewHolder(viewHolder.itemView) { | |
val viewHolder = viewHolder | |
} | |
class SingleViewRecycleAdapter(view: View) : RecyclerView.Adapter<SingleViewRecycleAdapter.ViewHolder>() { | |
var showContent = true | |
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) | |
val viewHolder = ViewHolder(view) | |
override fun getItemCount(): Int = if (showContent) 1 else 0 | |
override fun onBindViewHolder(holder: ViewHolder?, position: Int) { | |
//nop | |
} | |
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder? = viewHolder | |
} | |
class RecyclerViewWrapper<out T>(adapter: RecyclerView.Adapter<T>) where T : RecyclerView.ViewHolder { | |
private var adapter = adapter | |
fun isAdapter(adapter: RecyclerView.Adapter<*>): Boolean { | |
return this.adapter === adapter | |
} | |
fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolderWrapper { | |
return ViewHolderWrapper(adapter.onCreateViewHolder(parent, viewType)) | |
} | |
@Suppress("UNCHECKED_CAST") | |
fun onBindViewHolder(holder: ViewHolderWrapper, position: Int) { | |
adapter.bindViewHolder(holder.viewHolder as T, position) | |
} | |
fun getItemViewType(position: Int): Int = adapter.getItemViewType(position) | |
fun getItemCount(): Int = adapter.itemCount | |
} | |
class ViewTypeIndexer(private val reIndex: ViewTypeIndexer.() -> Unit) { | |
private var currentType = 0 | |
// viewType -> (adapterindex, adapterviewtype) | |
private var typeList = mutableMapOf<Int, Pair<Int, Int>>() | |
// adapterindex -> adapterviewtype -> viewtype | |
private var typeLookup = mutableMapOf<Int, MutableMap<Int, Int>>() | |
// index -> viewtype | |
private var indexLookup = mutableListOf<Int>() | |
val type: Map<Int, Pair<Int, Int>> get() { | |
initIfNeeded(); return typeList | |
} | |
val index: List<Int> get() { | |
initIfNeeded(); return indexLookup | |
} | |
fun addIndex(adapterIndex: Int, adapterViewType: Int) { | |
val viewType = typeLookup.getOrPut(adapterIndex) { mutableMapOf() }.getOrPut(adapterViewType) { currentType++ } | |
indexLookup.add(viewType) | |
typeList.put(viewType, Pair(adapterIndex, adapterViewType)) | |
} | |
fun initIfNeeded() { | |
if (typeList.isEmpty()) { | |
reIndex() | |
} | |
} | |
fun reset() { | |
typeList.clear() | |
indexLookup.clear() | |
} | |
} | |
class RecyclingMergeAdapter() : RecyclerView.Adapter<ViewHolderWrapper>() { | |
private var adapters = mutableListOf<RecyclerViewWrapper<RecyclerView.ViewHolder>>() | |
private var indexer = ViewTypeIndexer { | |
adapters.forEachIndexed { i, adapter -> | |
for (index in 0..adapter.getItemCount() - 1) { | |
addIndex(i, adapter.getItemViewType(index)) | |
} | |
} | |
} | |
val indexClearDataObserver = object : RecyclerView.AdapterDataObserver() { | |
override fun onChanged() { | |
resetIndex() | |
} | |
} | |
init { | |
registerAdapterDataObserver(indexClearDataObserver) | |
} | |
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolderWrapper? { | |
val p = indexer.type[viewType]!! | |
return adapters[p.first].onCreateViewHolder(parent, p.second) | |
} | |
override fun onBindViewHolder(holder: ViewHolderWrapper, position: Int) { | |
var count = 0 | |
for (adapter in adapters) { | |
count += adapter.getItemCount() | |
if (position < count) { | |
val pos = position - (count - adapter.getItemCount()) | |
adapter.onBindViewHolder(holder, pos) | |
return | |
} | |
} | |
throw Exception("We should never get here!") | |
} | |
override fun getItemViewType(position: Int): Int { | |
return indexer.index[position] | |
} | |
override fun getItemCount(): Int { | |
return adapters.map { it.getItemCount() }.sum() | |
} | |
fun positionInMergeAdapter(adapter: RecyclerView.Adapter<*>, positionInAdapter: Int): Int { | |
var count = 0 | |
for (a in adapters) { | |
if (a.isAdapter(adapter)) { | |
return count + positionInAdapter | |
} | |
count += a.getItemCount() | |
} | |
return 0 | |
} | |
fun resetIndex() { | |
indexer.reset() | |
} | |
fun <T : RecyclerView.ViewHolder> addAdapter(adapter: RecyclerView.Adapter<T>) { | |
indexer.reset() | |
adapters.add(RecyclerViewWrapper(adapter)) | |
adapter.registerAdapterDataObserver(indexClearDataObserver) | |
} | |
fun addView(view: View): SingleViewRecycleAdapter { | |
val adapter = SingleViewRecycleAdapter(view) | |
addAdapter(adapter) | |
return adapter | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment