Skip to content

Instantly share code, notes, and snippets.

@heinrisch
Last active January 25, 2017 15:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heinrisch/9250cad3c61b4fc71913cb94fe053d4d to your computer and use it in GitHub Desktop.
Save heinrisch/9250cad3c61b4fc71913cb94fe053d4d to your computer and use it in GitHub Desktop.
Now it works with animations! Reset the index before calling notifyItemXXX
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