Saving Scroll Positions of Nested RecyclerViews
One of the most annoying things when using RecyclerViews is that by nature they don’t store item states upon recycling. Thus, each item resets to its original state from creation as soon as you scroll away from the view. And the issue with nested RecyclerView carousels is that each carousel loses the index that was scrolled to originally. Makes you wonder, is there a trend being practiced in over-the-top apps like Netflix, Prime Video, Disney+, or even Google Play Store? The answer is yes.
Storing the carousel states
The idea behind this solution is that we will save the current scroll index of each horizontal carousel in some data structure before it is recycled. This way when the views return to foreground we can retrieve the saved indices and set the scroll positions for the carousels.
Few things to consider:
- All changes should be done in the outer adapter.
- We should store a
LinearLayoutManager
in the view holder and instantiate it upon creating its inner RecyclerView. - Fun fact: you can get the parent context in an adapter without passing it to the constructor inside
onCreateViewHolder
withmContext = viewGroup.getContext()
- Create a
SparseIntArray
or map to hold the scroll position of each carousel.
Now override the onViewRecycled
to store the position of the first visible item in that carousel after the view holder recycles.
Retrieving carousel states
Now that the states are stored we can retrieve them dynamically in onBindViewHolder
per position.
We have now just created an adapter that maintains the states of a carousel when it is recycled through the list! Although this solution works best when SnapHelper is used for the carousel, since the positions closest to the first visible item is used as a reference point. This technique can be used to store and retrieve data and complex views with similar list patterns.
Hope this helps!