Created
September 13, 2021 09:24
-
-
Save kakajika/7020951106a21753ea64df743e54b2e6 to your computer and use it in GitHub Desktop.
Concat multiple androidx.leanback.widget.ObjectAdapter like androidx.recyclerview.widget.ConcatAdapter
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
class ConcatObjectAdapter( | |
private vararg val adapters: ObjectAdapter | |
) : ObjectAdapter() { | |
init { | |
adapters.forEach { adapter -> | |
adapter.registerObserver(object : DataObserver() { | |
override fun onChanged() { | |
super.onChanged() | |
[email protected]() | |
} | |
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) { | |
super.onItemRangeChanged(positionStart, itemCount) | |
val offset = countItemsBefore(adapter) | |
[email protected]( | |
positionStart + offset, | |
itemCount | |
) | |
} | |
override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) { | |
super.onItemRangeChanged(positionStart, itemCount, payload) | |
val offset = countItemsBefore(adapter) | |
[email protected]( | |
positionStart + offset, | |
itemCount, | |
payload | |
) | |
} | |
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { | |
super.onItemRangeInserted(positionStart, itemCount) | |
val offset = countItemsBefore(adapter) | |
[email protected]( | |
positionStart + offset, | |
itemCount | |
) | |
} | |
override fun onItemMoved(fromPosition: Int, toPosition: Int) { | |
super.onItemMoved(fromPosition, toPosition) | |
val offset = countItemsBefore(adapter) | |
[email protected]( | |
fromPosition + offset, | |
toPosition + offset | |
) | |
} | |
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) { | |
super.onItemRangeRemoved(positionStart, itemCount) | |
val offset = countItemsBefore(adapter) | |
[email protected]( | |
positionStart + offset, | |
itemCount | |
) | |
} | |
}) | |
} | |
presenterSelector = object : PresenterSelector() { | |
override fun getPresenter(item: Any): Presenter { | |
return adapters.firstNotNullOf { | |
if (it.hasItemOfType(item::class.java)) { | |
try { it.getPresenter(item) | |
} catch (e: Exception) { null } | |
} else { | |
null | |
} | |
} | |
} | |
override fun getPresenters(): Array<Presenter> { | |
return adapters | |
.flatMap { it.presenterSelector.presenters.asList() } | |
.toTypedArray() | |
} | |
} | |
} | |
fun dispose() { | |
adapters.forEach { it.unregisterAllObservers() } | |
} | |
override fun size(): Int { | |
return adapters.sumOf { it.size() } | |
} | |
override fun get(position: Int): Any { | |
return resolveAdapterIndex(position) | |
?.let { (adapter, index) -> adapter.get(index) } | |
?: throw IllegalStateException() | |
} | |
override fun getId(position: Int): Long { | |
return resolveAdapterIndex(position) | |
?.let { (adapter, index) -> adapter.getId(index) } | |
?: throw IllegalStateException() | |
} | |
private fun countItemsBefore(adapter: ObjectAdapter): Int { | |
return adapters | |
.takeWhile { it !== adapter } | |
.sumOf { it.size() } | |
} | |
private fun resolveAdapterIndex(globalIndex: Int): Pair<ObjectAdapter, Int>? { | |
var offset: Int = 0 | |
for (adapter in adapters) { | |
if (globalIndex in offset until offset+adapter.size()) { | |
return Pair(adapter, globalIndex - offset) | |
} | |
offset += adapter.size() | |
} | |
return null | |
} | |
private fun <T> ObjectAdapter.hasItemOfType(clazz: Class<T>): Boolean { | |
for (i in 0 until size()) { | |
if (clazz.isInstance(get(i))) return true | |
} | |
return false | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment