4

I'm using the Navigation Component with a BottomNavigationView in my app. It switches between 4 destinations one of which contains a fragment with a RecyclerView containing hundreds of items. When I use the back button the RecyclerView restores with the previous scroll position. But When I use BottomNavigationView to switch between destinations, It won't restore to previous position and resets to the top of RecyclerView. Here's the code I tried to prevent that

    override fun onPause() {
    super.onPause()

    lastScrollPos = linearLayoutManager.findFirstVisibleItemPosition()
    }

    override fun onResume() {
        super.onResume()

        card_recyclerView.layoutManager?.scrollToPosition(lastScrollPos)
}

This is not workign what is the best way of restoring RecyclerView to correct position?

Amol Borkar
  • 2,321
  • 7
  • 32
  • 63

3 Answers3

2

The reason why it does not scroll to the previous position is the navController recreates the fragment (using replace) when used with the bottomNavigation.

A simple approach to save the scroll state is to store the layoutManager state in onDestroyView and restore it on onCreateView unlike the scrollToPosition this approach will scroll to the exact position when the NavController recreates the fragment.

I posted full code in another thread https://stackoverflow.com/a/66940957/2102794

Sai
  • 15,188
  • 20
  • 81
  • 121
0

This can be done by saving the Y-Axis position of the ScrollView in a member variable and restore it in onCreateView(). This works because the member variables are not destroyed.

class DiscoverDataFragment : BaseFragment() {
    private var loaded = false
    private var scrollPos = 0
    
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_discover_data, container, false)
    }
    
    override fun onCreateBind() {
        super.onCreateBind()  
        if (!loaded) {
            // Load views here
            loaded = true
        }
        
        if (scrollPos > 0) {
            scrollDiscoverData.scrollY = scrollPos
        }
    
        setScrollListener()
    }
    
    private fun setScrollListener() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            scrollDiscoverData.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
            scrollPos = scrollY
        }
    }
}
Elletlar
  • 3,136
  • 7
  • 32
  • 38
-2

you must initialize adapter outside fragment lifecycle, for example

class MyFragment : Fragment() {

private val myViewModel by viewModel<MyViewModel>()
private lateinit var myAdapter : MyAdapter

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    myAdapter = MyAdapter()
    Log.d("checkListData", myAdapter.currentList.toString())
    myViewModel.someListData.observe(viewLifecycleOwner){ listData ->
        myAdapter.submitList(listData)
    }
}}
Eko Yulianto
  • 145
  • 2
  • 5