Last active
February 10, 2021 14:10
-
-
Save cmorigaki/67a19b0866ca3b57af076062a89930c4 to your computer and use it in GitHub Desktop.
[Nested RecyclerView State] - View recreation or refresh list
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
| abstract class NestedRecyclerViewStateRecoverAdapter<T, VH : RecyclerView.ViewHolder>( | |
| diffUtil: DiffUtil.ItemCallback<T> | |
| ) : ListAdapter<T, VH>(diffUtil) { | |
| private val layoutManagerStates = hashMapOf<String, Parcelable?>() | |
| private val visibleScrollableViews = hashMapOf<Int, ViewHolderRef>() | |
| @CallSuper | |
| override fun onViewRecycled(holder: VH) { | |
| if (holder is NestedRecyclerViewViewHolder) { | |
| // Save the scroll position state (LayoutManager state) | |
| val state = holder.getLayoutManager()?.onSaveInstanceState() | |
| layoutManagerStates[holder.getId()] = state | |
| // State saved and view is not visible | |
| visibleScrollableViews.remove(holder.hashCode()) | |
| } | |
| super.onViewRecycled(holder) | |
| } | |
| @CallSuper | |
| override fun onBindViewHolder(holder: VH, position: Int) { | |
| if (holder is NestedRecyclerViewViewHolder) { | |
| holder.getLayoutManager()?.let { | |
| // Retrieve and set the saved LayoutManager state | |
| val state: Parcelable? = layoutManagerStates[holder.getId()] | |
| if (state != null) { | |
| it.onRestoreInstanceState(state) | |
| } else { | |
| // We need to reset the scroll position when no state needs to be restored | |
| it.scrollToPosition(0) | |
| } | |
| } | |
| visibleScrollableViews[holder.hashCode()] = ViewHolderRef( | |
| holder.getId(), | |
| WeakReference(holder as NestedRecyclerViewViewHolder) | |
| ) | |
| } | |
| } | |
| @CallSuper | |
| override fun submitList(list: List<T>?) { | |
| // We need to save the state from visible views before updating/setting the list to preserve | |
| // their states | |
| saveState() | |
| super.submitList(list) | |
| } | |
| private fun saveState() { | |
| visibleScrollableViews.values.forEach { item -> | |
| item.reference.get()?.let { | |
| layoutManagerStates[item.id] = it.getLayoutManager()?.onSaveInstanceState() | |
| } | |
| } | |
| visibleScrollableViews.clear() | |
| } | |
| fun clearState() { | |
| layoutManagerStates.clear() | |
| visibleScrollableViews.clear() | |
| } | |
| private data class ViewHolderRef( | |
| val id: String, | |
| val reference: WeakReference<NestedRecyclerViewViewHolder> | |
| ) | |
| } | |
| // ViewHolders containing a RecyclerView should inherit this interface. | |
| // An alternative solution could be manually searching if the view constains a RecyclerView | |
| interface NestedRecyclerViewViewHolder { | |
| fun getId(): String | |
| fun getLayoutManager(): RecyclerView.LayoutManager? | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment