How can I control the scrolling speed of recyclerView.smoothScrollToPosition(position)?
AndroidAndroid RecyclerviewAndroid Problem Overview
I have a recycler view, and I want a smooth scrolldown and then scrollup to it programatically to show the complete content in it to user.
I can do this by:
final int height=recyclerView.getChildAt(0).getHeight();
recyclerView.smoothScrollToPosition(height);
recyclerView.postDelayed(new Runnable() {
public void run() {
recyclerView.smoothScrollToPosition(0);
}
},200);
But what I want is to slow down the scrolling speed, so that the complete content gets visible clearly.
Android Solutions
Solution 1 - Android
Just to improve on the answer a little:
public class SpeedyLinearLayoutManager extends LinearLayoutManager {
private static final float MILLISECONDS_PER_INCH = 5f; //default is 25f (bigger = slower)
public SpeedyLinearLayoutManager(Context context) {
super(context);
}
public SpeedyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public SpeedyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
final LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return super.computeScrollVectorForPosition(targetPosition);
}
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
And then set SpeedyLayoutManager to your RecyclerView:
recyclerView.setLayoutManager(new SpeedyLinearLayoutManager(context, SpeedyLinearLayoutManager.VERTICAL, false);
Solution 2 - Android
For those uninterested in overriding LinearLayoutManager (or whichever subclass you're using), you can just call startSmoothScroll(smoothScroller)
directly on the layout manager.
LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
linearSmoothScroller.setTargetPosition(position);
layoutManager.startSmoothScroll(linearSmoothScroller);
Solution 3 - Android
I found an answer!
You need to make a custom class extending [LinearLayoutManager][1]
and then override the [smoothScrollToPosition][1]
method. Inside, you need to create a new [LinearSmoothScroller][1]
and override its calculateSpeedPerPixel method Then use that LinearSmoothScroller
to complete the scroll.
Here is my example :
public class CustomLinearLayoutManager extends LinearLayoutManager{
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
final LinearSmoothScroller linearSmoothScroller =
new LinearSmoothScroller(recyclerView.getContext()) {
private static final float MILLISECONDS_PER_INCH = 100f;
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return CustomLinearLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
@Override
protected float calculateSpeedPerPixel
(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
Assign this CustomLinearLayoutManager
to your RecyclerView
and you should be good to go. Let me know if I was unclear in anything. I'll be happy to help.
Solution 4 - Android
I've made a version that you can set the scrolling speed variable.
If you set factor
to 2, it will be twice as slow as default.
public class VariableScrollSpeedLinearLayoutManager extends LinearLayoutManager {
private final float factor;
public VariableScrollSpeedLinearLayoutManager(Context context, float factor) {
super(context);
this.factor = factor;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
final LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return VariableScrollSpeedLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return super.calculateSpeedPerPixel(displayMetrics) * factor;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
Solution 5 - Android
Based on @Bartek Mrozinski's answer. This is my Kotlin extension function for smoothly scroll the RecyclerView in a given time .
fun RecyclerView.smoothSnapToPosition(position: Int, snapMode: Int = LinearSmoothScroller.SNAP_TO_START) {
val scrollDuration = 500f;
val smoothScroller = object : LinearSmoothScroller(this.context) {
override fun getVerticalSnapPreference(): Int = snapMode
override fun getHorizontalSnapPreference(): Int = snapMode
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics?): Float {
return scrollDuration / computeVerticalScrollRange();
}
}
smoothScroller.targetPosition = position
layoutManager?.startSmoothScroll(smoothScroller)
}
Solution 6 - Android
To smoothly scroll the RecyclerView
in a given time You can override the LinearSmoothScroller#calculateSpeedPerPixel
like in example below.
final Context context = getContext();
final RecyclerView recyclerView = new RecyclerView(context);
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);
final YourCustomAdapter adapter = new YourCustomAdapter();
recyclerView.setAdapter(new YourCustomAdapter());
final float scrollDuration = 30000f; // in milliseconds
final LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return scrollDuration / recyclerView.computeVerticalScrollRange();
}
};
linearSmoothScroller.setTargetPosition(adapter.getItemCount() - 1);
layoutManager.startSmoothScroll(linearSmoothScroller);
Solution 7 - Android
//i am using the handler..
//where cretedactivtyadapter is my adpater classs
// instiate your adpter class like this
private CreatedActivityAdapter createdActivityAdapter;
//call autoscroll in your oncreate//
public void autoscroll()
{ ////auto scroll is used for the recycler view to scroll it self
final int speedScroll = 1;
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
int count = 0;
@Override
public void run()
{
if (count == createdActivityAdapter.getItemCount())
count=0;
if (count < createdActivityAdapter.getItemCount()){
recyclerView.smoothScrollToPosition(++count);
handler.postDelayed(this,speedScroll);
}
}
};
handler.postDelayed(runnable,speedScroll);
}
//and call theis handler in your on create
Solution 8 - Android
I got it like this horizontally
private val milliSecondsPerInch = 500f
var horizontalLayoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
onCreate
horizontalLayoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recycler_banner?.layoutManager = horizontalLayoutManager
and then
val linearSmoothScroller: LinearSmoothScroller =
object : LinearSmoothScroller(this) {
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
return milliSecondsPerInch / displayMetrics.densityDpi
}
}
linearSmoothScroller.targetPosition = 3 //the last position of the item in the list
horizontalLayoutManager.startSmoothScroll(linearSmoothScroller)