airbnb / epoxy

Epoxy is an Android library for building complex screens in a RecyclerView
https://goo.gl/eIK82p
Apache License 2.0
8.46k stars 730 forks source link

What is the proper way to save the scroll position in an EpoxyRecyclerView? #1287

Open martymiller opened 2 years ago

martymiller commented 2 years ago

When I use the back button to return to my Fragment (which is only a vertical EpoxyRecyclerView using MvRx) it starts at the top of the list instead of the screen. This is probably annoying for users who click on a photo, see the full screen image, and then end up at the top of the screen when hitting back. Is this something Android should be doing automatically? Should I be storing the scroll position in onSavedInstanceState? Or does Epoxy have some other solution?

I know that I can set saveViewState on Models, but I don't see how this would help the RecyclerView resume at the previous scroll position.

guozhiqiang123 commented 2 years ago

I have the same problem ! I use carousel within a vertical RecyclerView+Navigation,but carousel not saved the position.

abdul-hasib commented 2 years ago

Perhaps it is worth checking where the controller is being initialized, I have faced this issue when controllers are initialized/loaded during the onStart or onResume methods of Fragment however when it is done during the onCreateView method, it worked as expected.

xuexixuexijpg commented 2 years ago

I have the same problem ! I use carousel within a vertical RecyclerView+Navigation,but carousel not saved the position.

The location information can be saved. The Navigation I am currently using is the latest version, and it is done in combination with mavericks and epoxy. The scrolling position can also be saved when rotating the screen.But I haven't tried the compose version yet. (可以保存位置信息,我目前使用的Navigation是最新版,以及mavericks结合epoxy来做的,旋转屏幕时滚动的位置一样可以保存,不过compose版本的我还没试过)

Veeksi commented 2 years ago

I am also having this exact same issue where nested recyclerview contains horizontal carousel and whenever I navigate to other page and back, the carousels position is not retained - I have overridden shouldSaveViewState and I have tried to initialize controller in onViewCreated and in onCreate without good results

xuexixuexijpg commented 2 years ago

I am also having this exact same issue where nested recyclerview contains horizontal carousel and whenever I navigate to other page and back, the carousels position is not retained - I have overridden shouldSaveViewState and I have tried to initialize controller in onViewCreated and in onCreate without good results

This is indeed the case. I did the same thing. Although my original method kept the scroll position, the adapterleaked. Now if I use this, it is no problem to empty the adapterwhen I leave the window, but the original scroll state is gone. I don't know how to solve it, maybe I can rewrite the navigationcomponent to not destroythe view when navigating?Just overlay the view. This is the BaseEpoxyFragment I wrote while practicing.

Kudlayra commented 1 year ago

I added onScrollListener to my EpoxyRecyclerView, than i use findLastCompletelyVisibleItemPosition() on every scroll, in this way i got the position and saved it. And after that i can scroll to this position anytime

viroth-ty commented 1 year ago

Share us your implemented code.

Kudlayra commented 1 year ago

this code will save current visible position on every scroll:

var position = 0
binding.epoxyRecyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
     override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                position = (recyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
     }
}

then we can scroll to this position this way: binding.epoxyRecyclerView.scrollToPosition(position)

in my case it helped

viroth-ty commented 1 year ago

This should work!

private val uiController: UIController by lazy {
    UIController()
}

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    uiController.onSaveInstanceState(outState)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    uiController.onRestoreInstanceState(savedInstanceState)
}