54

I am using Recyclerview with CardView. I am aware how to control speed on list view. But not for Recyclerview.

I searched a lot in found class name SmoothScroll. How to use that? I have no Idea! Right now Recyclerview by default scroll is fast.

UPDATE:

I Summarized Gil Answer with this

Community
  • 1
  • 1
Shabbir Dhangot
  • 8,954
  • 10
  • 58
  • 80
  • @XaverKapeller I want to implement Slow scrolling in RecyclerView. – Shabbir Dhangot Mar 02 '15 at 05:54
  • What do you mean with slow scrolling? Please explain more. Do you want to programmatically scroll to some other position? – Xaver Kapeller Mar 02 '15 at 05:56
  • Still don't understand. What scrolling speed? What are you talking about? The scrolling speed when you programmatically scroll to another position? – Xaver Kapeller Mar 02 '15 at 06:22
  • My RecyclerView is endless with Items (Near about 10000 Item). When user scrolls RecyclerView Its scrolling like a wind unable to see Items. So my idea is to slow down speed of scrolling. I hope Now you get What I am trying to say. – Shabbir Dhangot Mar 02 '15 at 06:47
  • So you mean when the user flings the `RecyclerView` or what? – Xaver Kapeller Mar 02 '15 at 16:46
  • @XaverKapeller no I mean scrolling a screen. – Shabbir Dhangot Mar 04 '15 at 08:48
  • I have no idea what you are talking about. If the user scrolls like normal with his finger on the screen then the data moves with the finger. I don't understand how you would ever get a situation in which ass you say "Its scrolling like a wind unable to see Items". – Xaver Kapeller Mar 04 '15 at 08:52
  • It happens when I move finger fast. and yes you got the point that scrolling with finger. – Shabbir Dhangot Mar 04 '15 at 13:58
  • @XaverKapeller Sorry, Actually I don't know that I actually want a fling. – Shabbir Dhangot Mar 05 '15 at 13:10
  • I you are after a solution for controlling the speed of the scroll, to scroll faster to more distant positions have a look at https://stackoverflow.com/a/63643036/3833411 – Vlad Aug 29 '20 at 06:36

4 Answers4

112

It's unclear what you mean when you say "smoothScroll". You could be referring to the automatic "smoothScrollToPosition" which will automatically scroll to a specified position, you could be talking about manual scrolling and you could be talking about flinging. For the sake of prosperity, I will attempt to answer all of these issues now.

1. Automatic smooth scrolling.

Inside your layout manager, you need to implement the smoothScrollToPosition method:

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, State state, int position)
    {
        // A good idea would be to create this instance in some initialization method, and just set the target position in this method.
        LinearSmoothScroller smoothScroller = new LinearSmoothScroller(getContext())
        {
            @Override
            public PointF computeScrollVectorForPosition(int targetPosition)
            {
                int yDelta = calculateCurrentDistanceToPosition(targetPosition);
                return new PointF(0, yDelta);
            }

            // This is the important method. This code will return the amount of time it takes to scroll 1 pixel.
            // This code will request X milliseconds for every Y DP units.
            @Override
            protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics)
            {
                return X / TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, Y, displayMetrics);
            }

        };
        smoothScroller.setTargetPosition(position);

        startSmoothScroll(smoothScroller);
    }

In this example, I use a helper method named "calculateCurrentDistanceToPosition". This can be a bit tricky, since it involves keeping track of your current scroll position, and calculating the scroll position of a given y position. You can find an example of how to keep track of the recycler's scroll y here.

Calculating the scroll y of a given position is really dependent on what your recycler is displaying. Assuming all your items are the same height, you can calculate this by performing the following calculation:

targetScrollY = targetPosition * itemHeight

Then, to calculate the distance you need to scroll, simply subtract the current scroll y with the target scroll y:

private int calculateCurrentDistanceToPosition(int targetPosition) {
    int targetScrollY = targetPosition * itemHeight;
    return targetScrollY - currentScrollY;
}

2. Slowing down manual scrolling.

Once again, you need to edit your layout manager, this time - the scrollVerticallyBy method:

    @Override
    public int scrollVerticallyBy(int delta, Recycler recycler, State state)
    {
       // write your limiting logic here to prevent the delta from exceeding the limits of your list.

       int prevDelta = delta;
       if (getScrollState() == SCROLL_STATE_DRAGGING)
            delta = (int)(delta > 0 ? Math.max(delta * MANUAL_SCROLL_SLOW_RATIO, 1) : Math.min(delta * MANUAL_SCROLL_SLOW_RATIO, -1));  

       // MANUAL_SCROLL_SLOW_RATIO is between 0 (no manual scrolling) to 1 (normal speed) or more (faster speed).
       // write your scrolling logic code here whereby you move each view by the given delta

        if (getScrollState() == SCROLL_STATE_DRAGGING)
            delta = prevDelta;

        return delta;
    }

Edit: In the above method, I call "getScrollState()". This is a method of RecyclerView. In this implementation, my custom LayoutManager is a nested class of my custom RecyclerView. If this doesn't work for you, you can try to grab the scroll state via some interface pattern.

3. Slow down the fling speed

Here you want to scale down the fling velocity. You will need to override the fling method inside your RecyclerView subclass:

@Override
public boolean fling(int velocityX, int velocityY)
{
     velocityY *= FLING_SCALE_DOWN_FACTOR; // (between 0 for no fling, and 1 for normal fling, or more for faster fling).

     return super.fling(velocityX, velocityY);
}

It's difficult for me to provide a more tailored solution, since you didn't post any of your code, or provide much information about your setup, but I hope this covers most bases and will help you find the best solution for you.

Community
  • 1
  • 1
Gil Moshayof
  • 16,633
  • 4
  • 47
  • 58
  • What I want is to scroll down manual scrolling your second point. But methods and variables there are undefined. can you please update this. – Shabbir Dhangot Mar 04 '15 at 13:55
  • I'm afraid that in order to help you any further, I'll need you to post more of your code so I can understand what you're doing and where you're stuck. – Gil Moshayof Mar 04 '15 at 13:59
  • If instead of creating your own layout manager, your give the RecyclerView a new LinearLayoutManager, does the scrolling issue stop? – Gil Moshayof Mar 05 '15 at 08:33
  • You copied my code sample, but didn't adapt it to your needs... "dy" needs to be refactored to "detla", MANUAL_SCROLL_SLOW_RATIO is a final static variable which you must define, and should be between 0 and 1, and of course, you need to implement your own logic for adjusting the positions of all the views, as well as detatching / scrapping unneeded views. – Gil Moshayof Mar 05 '15 at 08:34
  • Okk I understand. But using with new LinearLayoutManager facing same issue. I cant understand my mistake. I follow your guideline and create new class. its not giving error now. but I unable to see recycler view at runtime. Is anything I need to put in getDefaultLayoutParams() or any other method. – Shabbir Dhangot Mar 05 '15 at 10:45
  • This looks pretty good, but what's the deal with `getScrollState()`? That doesn't do anything for me in the LayoutManager class. – Wenger Mar 11 '15 at 14:32
  • The idea here is to ensure that the user is manually dragging. scrollVerticallyBy gets called by automatic smooth scrolls and flings. If you want to slow down (or speed up) manual scrolling (i.e., items will follow your finger at different speeds than your finger), then you should use this method. – Gil Moshayof Mar 11 '15 at 14:46
  • I got all that, but there isn't a `getScrollState()` method available in that class unless it points to a custom one that retrieves scroll state through some other means. – Wenger Mar 11 '15 at 14:48
  • Of course! I should have mentioned that in this implementation, my layout manager is a nested class of my recyclerview. Ill edit the answer shortly. Thank you. – Gil Moshayof Mar 11 '15 at 14:51
  • Wow, the first one (overriding `calculateSpeedPerPixel`) is pretty clever. Good job! Although overriding `computeScrollVectorForPosition` can be achieved with just a simple `.this.computeScrollVectorForPosition(targetPosition);` – Bartek Lipinski Apr 14 '15 at 09:37
  • @GilMoshayof any idea how can I take offset into account aswell ? if i intend to do scrollToPositionWithOffset(pos,offset) instead of smoothScrollToPosition() ? – ShahrozKhan91 Apr 22 '15 at 06:52
  • 2
    and calculateCurrentDistanceToPosition() ? where do you get this from? – rubmz Dec 02 '15 at 08:38
  • This method is up to you to implement but can be fairly simple if you keep track of how far you've scrolled in your layout manager, and if you have a way of knowing the scroll position of a certain element. Then you basically return targetScrollOffset - currentScrollOffset. If you'd like to know more, perhaps consider opening a new SO question and link it here so I can answer it. – Gil Moshayof Dec 02 '15 at 09:19
  • I read this answer and it work for me. http://stackoverflow.com/questions/31249252/how-to-make-recyclerview-scroll-smoothly – Ninja Apr 29 '17 at 08:58
  • Hey @GilMoshayof can you please help me with this https://stackoverflow.com/questions/49952965/recyclerview-horizontal-scrolling-to-left?noredirect=1#comment87861669_49952965 –  May 19 '18 at 08:51
36

I just simplifying Answer how to use it to control smooth scroll.

Create Class

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;

public class CustomRecyclerView extends RecyclerView {

    Context context;

    public CustomRecyclerView(Context context) {
        super(context);
        this.context = context;
    }

    public CustomRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean fling(int velocityX, int velocityY) {

        velocityY *= 0.7;
        // velocityX *= 0.7; for Horizontal recycler view. comment velocityY line not require for Horizontal Mode.

        return super.fling(velocityX, velocityY);
    }

}

Adjust speed by Replacing 0.7 to your value.

Now use this class in your XML like this.

<<yourpackage>.CustomRecyclerView
    android:id="@+id/my_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical" />

Read RecyclerView in Java like.

CustomRecyclerView mRecyclerView;
mRecyclerView = (CustomRecyclerView) findViewById(R.id.my_recycler_view);
Shabbir Dhangot
  • 8,954
  • 10
  • 58
  • 80
36

Simply implement smoothScrollToPosition() of your LinearLayoutManager:

LinearLayoutManager layoutManager = new LinearLayoutManager(this) {

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        LinearSmoothScroller smoothScroller = new LinearSmoothScroller(this) {

            private static final float SPEED = 300f;// Change this value (default=25f)

            @Override
            protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                return SPEED / displayMetrics.densityDpi;
            }

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

};
Blunderer
  • 934
  • 7
  • 15
0

use this for smooth scrolling

recyclerViewCart.isNestedScrollingEnabled = false
Sandeep Pareek
  • 1,636
  • 19
  • 21
  • I recommend that you add comments to your code as it will help other members to understand what you intended with this code. – Joe Ferndz Dec 29 '20 at 08:33