DEV Community

Aldo Wachyudi
Aldo Wachyudi

Posted on

How to scroll RecyclerView to a certain position?

This questions seems so simple, in fact Android SDK has provided several API to scroll item at certain position.



fun iJustWantToScroll() {
    recyclerView.scrollToPosition()
    recyclerView.smoothScrollToPosition()
    recyclerView.layoutManager?.scrollToPosition()
    (recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset()    
}


Enter fullscreen mode Exit fullscreen mode

It should work as expected right? Afterall, scrolling an item to certain position is a fairly common usage. Yet, why does this question is still popular?

scrolltoposition

Me too, is a victim of this bug. I have spent years before I realised I was asking the wrong question, before I'll answer this question, let me show you what I previously had done before.



fun iJustWantToScroll() {
    recyclerView.postDelayed(Runnable {
        // or use other API
        recyclerView.smoothScrollToPosition(0)

        // give a delay of one second
    }, 1_000)
}


Enter fullscreen mode Exit fullscreen mode

This is a bit hacky, but always works (in my scenario). Try to reduce the delay, usually 500 milliseconds is enough.


The right question to ask about scrollToPosition is not How, but When.

When to scroll RecyclerView to a certain position?

I find that the problem why scrollToPosition , and others API, does not work is because the dataset is not yet ready. We should call scrollToPosition when the recyclerView has received dataset. To do that, we can use AdapterDataObserver.

AdapterDataObserver on d.android

AdapterDataObserver has five public methods.

public-methods

As the method name implies, onItemRangeInserted is called when an item is added to the RecyclerView, and onItemRemoved is called when an item is removed from the RecyclerView.

There is an exception for onChanged. onChangedis only called when you call notify on an Adapter, it is not going to called everytime there is a change on the RecyclerView.

I usually call scrollToPosition when the dataset is succesfully inserted to a RecyclerView, for example:



adapter.registerAdapterDataObserver( object : RecyclerView.AdapterDataObserver() {
    override fun onItemRangeInserted(
        positionStart: Int,
        itemCount: Int
    ) {
        recyclerView.scrollToPosition(0)
    }

    override fun onItemRangeRemoved(
        positionStart: Int,
        itemCount: Int
    ) {
        recyclerView.smoothScrollToPosition(itemCount)
    }
}


Enter fullscreen mode Exit fullscreen mode

This way, we don't have to wait certain millisecond to scroll a ReyclerView. When there is a new dataset, we can trigger scrollToPosition or smoothScrollToPosition and be sure RecyclerView is scrolled.

Top comments (7)

Collapse
 
nabinadhikari profile image
Nabin Adhikari

Very interesting, Thanks

Collapse
 
gunjotsinghmansa profile image
gunjotSinghMansa

Saved me !!

Collapse
 
fen31 profile image
fen31

OOOooooo thanks!

Collapse
 
sadegh8 profile image
Sadegh

perfect! thanks

Collapse
 
jamesortiz profile image
James Ortiz

Thanks, helped me a lot!

Collapse
 
surajsahani profile image
Suraj Sahani

good article, m question how we should store the recyclerview position in background

Collapse
 
aldok profile image
Aldo Wachyudi

Good article. My question is how should we store the RecyclerView position in the background?

Thank you!

It depends on what you mean by background. If you mean storing it while the app is in the background, you can save the position in the onPause method and restore it in the onResume method.

If you want to retain the position after the app is closed, you can store it in a persistence layer using SharedPreferences or Room.