如何控制recyclerView.smoothScrollToPosition(position)的滚动速度?

问题描述 投票:0回答:9

我有一个回收器视图,我想要平滑地向下滚动,然后以编程方式向上滚动到它,以向用户显示其中的完整内容。

我可以通过以下方式做到这一点:

    final int height=recyclerView.getChildAt(0).getHeight();
    recyclerView.smoothScrollToPosition(height);
    recyclerView.postDelayed(new Runnable() {
        public void run() {
            recyclerView.smoothScrollToPosition(0);
                        }
    },200);

但我想要的是减慢滚动速度,以便完整的内容清晰可见。

android android-recyclerview
9个回答
133
投票

只是为了稍微改进一下答案:

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);
    }
}

然后将 SpeedyLayoutManager 设置为您的 RecyclerView:

recyclerView.setLayoutManager(new SpeedyLinearLayoutManager(context, SpeedyLinearLayoutManager.VERTICAL, false);

56
投票

对于那些对重写 LinearLayoutManager (或您正在使用的任何子类)不感兴趣的人,您可以直接在布局管理器上调用

startSmoothScroll(smoothScroller)

LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {

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

linearSmoothScroller.setTargetPosition(position);
layoutManager.startSmoothScroll(linearSmoothScroller);

24
投票

我找到答案了!

您需要创建一个扩展

[LinearLayoutManager][1]
的自定义类,然后重写
[smoothScrollToPosition][1]
方法。在里面,您需要创建一个新的
[LinearSmoothScroller][1]
并重写其calculateSpeedPerPixel 方法,然后使用该
LinearSmoothScroller
来完成滚动。

这是我的例子:

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);
    }
}

将此

CustomLinearLayoutManager
分配给您的
RecyclerView
,您就可以开始了。如果我有任何不清楚的地方,请告诉我。我很乐意提供帮助。


15
投票

我制作了一个可以设置滚动速度变量的版本。

如果将

factor
设置为2,速度会比默认值慢两倍。

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);
    }
}

11
投票

基于@Bartek Mrozinski 的回答。这是我的 Kotlin 扩展函数,用于在给定时间内平滑滚动 RecyclerView。

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) 
}

5
投票

要在给定时间内平滑滚动

RecyclerView
您可以覆盖
LinearSmoothScroller#calculateSpeedPerPixel
,如下例所示。

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);

2
投票

我是这样横向的

  private val milliSecondsPerInch = 500f 
  var horizontalLayoutManager =  LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)

创建时

horizontalLayoutManager =  LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
recycler_banner?.layoutManager = horizontalLayoutManager

然后

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)

2
投票
//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);
}

//并在创建时调用 theis 处理程序


0
投票
class CustomLinearLayoutManager : LinearLayoutManager {

    constructor(context: Context) : super(context) {}

    constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout) {}

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {}

    companion object {
        private val SMOOTHNESS_DISTANCE_IN_PIXELS = 500f
        private val SMOOTHNESS_DURATION = 500f
    }

    override fun smoothScrollToPosition(recyclerView: RecyclerView, state: RecyclerView.State?, position: Int) {
        val linearSmoothScroller = object : LinearSmoothScroller(recyclerView.context) {
            override fun computeScrollVectorForPosition(targetPosition: Int): PointF? {
                return this@CustomLinearLayoutManager
                        .computeScrollVectorForPosition(targetPosition)
            }

            override fun calculateTimeForScrolling(dx: Int): Int {
                val proportion = dx.toFloat() / SMOOTHNESS_DISTANCE_IN_PIXELS
                return (SMOOTHNESS_DURATION * proportion).toInt()
            }
        }
        linearSmoothScroller.computeScrollVectorForPosition(position)
        linearSmoothScroller.targetPosition = position
        startSmoothScroll(linearSmoothScroller)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.