androidandroid-fragmentsandroid-viewpagerandroid-architecture-navigationstaggeredgridlayoutmanager

RecyclerView with StaggeredGridLayoutManager in ViewPager, arranges items automatically when going back to fragment


I am using Navigation component in my App, using google Advanced Sample(here). my problem is when going back to a fragment, the scrolling position does not lost but it rearranges items and moves highest visible items so that top of those item align to top of recyclerview. please see this:

enter image description here

before going to next fragment:

enter image description here

and after back to fragment:

enter image description here

this problem is matter because some times clicked item goes down and not seen until scroll down. how to prevent this behavior?

please consider:

UPDATE: you can clone project with this problem from here


Solution

  • When using Navigation Component + ViewPager + StaggeredGridLayoutManager, wrong recyclerView.computeVerticalScrollOffset() has been returned during Fragment recreate.

    In general, all layout managers bundled in the support library already know how to save and restore scroll position, but in this case, we had to take responsibility for this.

    class TestFragment : Fragment(R.layout.fragment_test) {
    
        private val testListAdapter: TestListAdapter by lazy {
            TestListAdapter()
        }
    
        private var layoutManagerState: Parcelable? = null
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            postListView.apply {
                layoutManager = StaggeredGridLayoutManager(
                    2, StaggeredGridLayoutManager.VERTICAL
                ).apply {
                    gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
                }
                setHasFixedSize(true)
    
                adapter = testListAdapter
            }
    
            testListAdapter.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT
    
        }
    
        override fun onPause() {
            saveLayoutManagerState()
            super.onPause()
        }
    
        override fun onViewStateRestored(savedInstanceState: Bundle?) {
            super.onViewStateRestored(savedInstanceState)
            restoreLayoutManagerState()
        }
    
        private fun restoreLayoutManagerState () {
            layoutManagerState?.let { postListView.layoutManager?.onRestoreInstanceState(it) }
        }
    
        private fun saveLayoutManagerState () {
            layoutManagerState = postListView.layoutManager?.onSaveInstanceState()
        }
    }
    

    Source code: https://github.com/dautovicharis/MyStaggeredListSample/tree/q_65539771