58

I'm using basic RecyclerView with GridLayoutManager. I observed that nor smoothScrollToPosition nor scrollToPosition works properly.

a) when using smoothScrollToPosition I often receive error from RecyclerView

"RecyclerView﹕ Passed over target position while smooth scrolling."

and RecyclerView is not scrolled properly (often it misses the targeted row). This is observed mostly when I'm trying to scroll to the 1st item of some row

b) when using scrollToPosition it seems to work quite ok but most of the time I can see only the 1st item of the row and the rest are not displayed.

Can you give me some hints how to make work properly at least one of the methods?

Thanks a lot!

MiguelHincapieC
  • 5,445
  • 7
  • 41
  • 72
petrushka1986
  • 1,485
  • 2
  • 11
  • 17
  • If you have a negative position (for instance, you want to reach last position in empty adapter), you will get an error: https://stackoverflow.com/questions/57937265/java-lang-illegalargumentexception-is-occuring. – CoolMind Aug 12 '20 at 10:24

18 Answers18

81

Finally I was able to make it work! LinearLayoutManager.scrollToPositionWithOffset(int, int) did the trick.

Floern
  • 33,559
  • 24
  • 104
  • 119
petrushka1986
  • 1,485
  • 2
  • 11
  • 17
  • 6
    I'm having a similar problem, and that method did the trick for me as well... but I'm actually trying to implement smoothScroll. Are you as well? – Phiat Jun 16 '15 at 17:57
  • Sorry for late answer: I was not able to do the smooth scroll. But it was not a requirement and in my case quick scroll looks better. Anyway good luck and don't forget to write here if you were successful! Thanks a lot. – petrushka1986 Jul 05 '15 at 20:29
  • 5
    Using `gridLayoutManager.scrollToPositionWithOffset(index, 0)` worked for me also. – droppin_science Jul 29 '16 at 09:50
  • working fine... Ex . layoutManager.scrollToPositionWithOffset(position, 0); – Surendar D Dec 22 '16 at 06:12
  • 5
    Yes, ```LayoutManager.scrollToPosition()``` may not work well, but `LinearLayoutManager.scrollToPositionWithOffset()` is good :D it's magic. – krosshj May 10 '17 at 12:59
  • working fine but scrollistener not working. if you want detect scroll, you should smoothScrollToPosition(int). – 최봉재 May 18 '17 at 07:41
  • 3
    Typical usage is: `LinearLayoutManager llm = (LinearLayoutManager) recyclerView.getLayoutManager(); llm.scrollToPositionWithOffset(10, 0);` But note that you no longer get the smooth scrolling animation that `smoothScrollToPosition()` had. – Mr-IDE Jul 30 '17 at 19:49
  • Perfect solution! Thank you. Works as charm – Олег Місько Nov 04 '17 at 09:43
  • I also confirm that this solution works perfectly fine. scrolltoPosition was often scrolling to items before what I was expecting (even by using the return value of findFirstCompletelyVisibleItem..), but the WithOffset version works like a charm! Thanks :) – Simon Ninon Dec 22 '17 at 01:03
  • 1
    Still the only solution that worked well after 3 years. – Shadow Jun 27 '19 at 13:43
  • Unbelievable this is the only solution that works well for just a simple feature!!! – Hoang Nguyen Huu Jun 10 '20 at 10:21
  • 3
    Not working! same as mRecyclerView.scrollToPosition(position) – Abu Nayem Sep 27 '20 at 09:03
  • Worked for me but it doesn't give animation. I take it as a backup plan. Still trying to figure out a better way. – Chinese Cat Oct 13 '21 at 07:10
  • Trying to make the scroll smooth again. Any suggestions? – Konstantin Konopko Dec 07 '22 at 17:50
18

I also have same issue, but managed to fix the issue by Customizing SmoothScroller

let Custom LayoutManager as below

public class CustomLayoutManager extends LinearLayoutManager {
    private static final float MILLISECONDS_PER_INCH = 50f;
    private Context mContext;

    public CustomLayoutManager(Context context) {
        super(context);
        mContext = context;
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView,
        RecyclerView.State state, final int position) {

        LinearSmoothScroller smoothScroller = 
            new LinearSmoothScroller(mContext) {

            //This controls the direction in which smoothScroll looks
            //for your view
            @Override
            public PointF computeScrollVectorForPosition
            (int targetPosition) {
                return CustomLayoutManager.this
                    .computeScrollVectorForPosition(targetPosition);
            }

            //This returns the milliseconds it takes to 
            //scroll one pixel.
            @Override
            protected float calculateSpeedPerPixel
                (DisplayMetrics displayMetrics) {
                return MILLISECONDS_PER_INCH/displayMetrics.densityDpi;
            }
        };

        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }
}

(documentation commented inside the code given above)Please set the above LayoutManager to the recyerview

CustomLayoutManagerlayoutManager = new CustomLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.smoothScrollToPosition(position);

by using the custom Layout manager

scrollToPosition also working well in my case u can use

recyclerView.scrollToPosition(position)

also if you want to adjust the speed of smoothScrollToPosition please override the

private static final float MILLISECONDS_PER_INCH = 50f;

in CustomLayoutManager. So if we put the value as 1f the smoothScrollToPosition will be faster like scrollToPosition.increasing value make delay and decreasing will make the speed of scroll. Hope this will useful.

MiguelHincapieC
  • 5,445
  • 7
  • 41
  • 72
Ramz
  • 7,116
  • 6
  • 63
  • 88
13

In My case,

mRecyclerView.scrollToPosition(10);

also did not work. But

mRecyclerView.smoothScrollToPosition(10);

works fine for me...

AskNilesh
  • 67,701
  • 16
  • 123
  • 163
zephyr
  • 665
  • 6
  • 19
8

To scroll down smoothly to bottom from any position in the RecyclerView on clicking EditText.

edittext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                rv_commentList.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                      rv_commentList.scrollToPosition(rv_commentList.getAdapter().getItemCount() - 1);
                    }
                }, 1000);
            }
        });
Muhammad Umair Shafique
  • 2,475
  • 1
  • 30
  • 39
7

Another reason why any of the before mentioned solutions may not work is if your RecyclerView is embedded in a NestedScrollView. In this case you have to call the scroll action on the NestedScrollView.

for example:

nestedScrollview.smoothScrollTo(0,0)
checkmate711
  • 3,301
  • 2
  • 35
  • 45
4

This extension is so useful, try please.

fun RecyclerView.smoothSnapToPosition(position: Int, snapMode: Int = LinearSmoothScroller.SNAP_TO_START) {
        val smoothScroller = object : LinearSmoothScroller(this.context) {
            override fun getVerticalSnapPreference(): Int = snapMode
            override fun getHorizontalSnapPreference(): Int = snapMode
        }
        smoothScroller.targetPosition = position
        layoutManager?.startSmoothScroll(smoothScroller)
    }
Sefa Ayçiçek
  • 111
  • 1
  • 1
3

I was facing a weird issue wherein smoothScrollToPosition only worked occasionally.

After putting the smoothScrollToPosition inside Handler Post Delayed with 1 second delay, it worked fine.

Refer to the following Kotlin example:

Handler().postDelayed({

   recyclerViewObject.smoothScrollToPosition(0) // mention the position in place of 0

}, 1000) // 1000 indicates the 1 second delay.
Arshak
  • 3,197
  • 1
  • 25
  • 33
2
recyclerView.getLayoutManager().smoothScrollToPosition(recyclerView,new RecyclerView.State(),currentPosition);
AskNilesh
  • 67,701
  • 16
  • 123
  • 163
Javid Sattar
  • 749
  • 8
  • 14
  • 2
    recyclerView. smoothScrollToPosition(position) called method that you described in comment. Can you explain why you set new state. recyclerView already has state ? – Rahul Mandaliya Feb 18 '20 at 12:25
1

Try measuring item width or height and call smoothScrollBy(int dx, int dy).

Dubrovin
  • 245
  • 3
  • 13
1

How to perform smooth scrolling and save RecyclerView vertical position after device rotating: This is the method that works for my case,

public class MainFragment extends Fragment { //OR activity it's //fragment in my case
    ....
 @Override
    public void onLoadFinished(@NonNull Loader<List<Report>> loader, List<Report> objects) { // or other method of your choice, in my case it's a Loader 
    RecyclerView recyclerViewRv = findViewById(........;
         .....
    recyclerViewRv.setAdapter(.....Your adapter);

            recyclerViewRv.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                }

                @Override
                public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    recyclerScrollY = recyclerViewRv. computeVerticalScrollOffset();
                }
            });

    //Apply smooth vertical scroll
    recyclerViewRv.smoothScrollBy(0,recyclerScrollY);
}
    //Save vertical scroll position before rotating devices
    @Override
        public void onSaveInstanceState(@NonNull Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putInt("recyclerScrollY",recyclerScrollY);
        }

    //BackUp vertical scroll position after rotating devices 
    @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if(savedInstanceState != null) {
                recyclerScrollY = savedInstanceState.getInt("recyclerScrollY");
            }
        }
//If you want to perform the same operation for horizontal scrolling just add a variable called recyclerScrollX = recyclerScrollY = recyclerViewRv. computeHorizontalScrollOffset(); then save in bundle
Venkatachalam
  • 16,288
  • 9
  • 49
  • 77
0

Calling the recyclerView smoothScroll isn't effective, as the recyclerView itself doesn't handle its layout.

What you should do is calling the layout manager scroll method instead.

This should look something like this

mRecyclerView.getLayoutManager().scrollToPosition(desiredPosition);
orelzion
  • 2,452
  • 4
  • 30
  • 46
0

If you are trying to do a quick scroll to a position at the top of the RecyclerView, just use LinearLayoutManager.scrollToPositionWithOffset with 0 as the offset.

Example:

mLinearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLinearLayoutManager);

mLinearLayoutManager.scrollToPositionWithOffset(myPosition, 0);

smoothScrollToPosition is very slow. If you want something fast go with scrollToPositionWithOffset.

live-love
  • 48,840
  • 22
  • 240
  • 204
0

when you use scrollToPosition it will show it on top of the recycler view.

But if you use smoothScrollToPosition it will scroll till it come in to Window Visible. that's why while smoothScrool to item below, it will show it on bottom

0

Actually, if you have a RecyclerView inside a NestedScrollView, you must use both of these lines every time you want to go to the beginning of the RecyclerView:

nestedScrollView.smoothScrollTo(0, 0);
layoutManager.scrollToPositionWithOffset(0, 0);

This completely works for me.

Arantik
  • 584
  • 8
  • 17
0

this worked for me

    Handler().postDelayed({
                    (recyclerView.getLayoutManager() as LinearLayoutManager).scrollToPositionWithOffset( 0, 0)

}, 100)
Quick learner
  • 10,632
  • 4
  • 45
  • 55
0

None of these answers worked for me. I needed to smoothScrollToPosition but @Ramz answer didn't work. I was finding it would consistently overscroll but only in one direction. I discovered that it seemed to be the item decorators throwing it off. I had a horizontal layout and I wanted to add a space after every item except the last and it didn't like that asymmetry. As soon as I included a space after every item, it worked!

hmac
  • 267
  • 3
  • 9
0
nestedScroll.smoothScrollTo(0, recycler.top)
Kishan Mevada
  • 662
  • 1
  • 6
  • 17
-1

So i was looking for a solution to get back to the top with a recyclerview inside another layout that has a view on top of it (in my case I had a LinearLayout with a TextView and my recyclerview inside). Because of that the smoothscroll would go only to half the way to the first item.

Here's what I did which works really well (Kotlin solution):

back_to_top.setOnClickListener {
        GlobalScope.launch(Dispatchers.Main) {
            GlobalScope.launch(Dispatchers.Main) {
                recyclerview.layoutManager?.smoothScrollToPosition(recyclerview, RecyclerView.State(), 0)
                delay((recyclerview.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() * 100L)
            }.join()
            recyclerview.scrollToPosition(0)
        }
        back_to_top.visibility = View.GONE
    }
}

Here what I do is I smoothscroll to the first element and delay the scroll by 100ms times the last item visible and then call the scrollToPosition(0) (which goes to the top.correctly)