Android:控制平滑滚动回收器视图

时间:2022-08-25 07:43:51

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

我正在使用Recyclerview和CardView。我知道如何控制列表视图的速度。但不适用于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.

我在找到的类名SmoothScroll中搜索了很多。怎么用?我不知道!现在,Recyclerview默认滚动很快。

UPDATE:

更新:

I Summarized Gil Answer with this

我总结了吉尔答案

3 个解决方案

#1


95  

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.

当你说“smoothScroll”时,你的意思还不清楚。您可以指自动“smoothScrollToPosition”,它将自动滚动到指定的位置,您可能正在谈论手动滚动,您可能正在谈论投掷。为了繁荣,我现在将尝试回答所有这些问题。

1. Automatic smooth scrolling.

1.自动平滑滚动。

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

在布局管理器中,您需要实现smoothScrollToPosition方法:

    @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.

在这个例子中,我使用名为“calculateCurrentDistanceToPosition”的辅助方法。这可能有点棘手,因为它涉及跟踪当前滚动位置,以及计算给定y位置的滚动位置。您可以在此处找到有关如何跟踪回收器滚动的示例。

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:

计算给定位置的滚动y实际上取决于回收者显示的内容。假设您的所有项目都是相同的高度,您可以通过执行以下计算来计算:

targetScrollY = targetPosition * itemHeight

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

然后,要计算您需要滚动的距离,只需使用目标滚动y减去当前滚动y:

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

2. Slowing down manual scrolling.

2.减慢手动滚动。

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

再一次,您需要编辑布局管理器,这次是scrollVerticallyBy方法:

    @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.

编辑:在上面的方法中,我调用“getScrollState()”。这是RecyclerView的一种方法。在此实现中,我的自定义LayoutManager是我的自定义RecyclerView的嵌套类。如果这对您不起作用,您可以尝试通过某种界面模式获取滚动状态。

3. Slow down the fling speed

3.减慢速度

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

在这里,您希望缩小投掷速度。您需要覆盖RecyclerView子类中的fling方法:

@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.

由于您没有发布任何代码或提供有关您的设置的大量信息,因此我很难提供更具针对性的解决方案,但我希望这涵盖了大多数基础,并将帮助您找到最适合您的解决方案。

#2


28  

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.

通过将0.7替换为您的值来调整速度。

Now use this class in your XML like this.

现在在这样的XML中使用这个类。

<<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.

阅读Java中的RecyclerView。

CustomRecyclerView mRecyclerView;
mRecyclerView = (CustomRecyclerView) findViewById(R.id.my_recycler_view);

#3


17  

Simply implement smoothScrollToPosition() of your LinearLayoutManager:

只需实现LinearLayoutManager的smoothScrollToPosition():

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

};

#1


95  

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.

当你说“smoothScroll”时,你的意思还不清楚。您可以指自动“smoothScrollToPosition”,它将自动滚动到指定的位置,您可能正在谈论手动滚动,您可能正在谈论投掷。为了繁荣,我现在将尝试回答所有这些问题。

1. Automatic smooth scrolling.

1.自动平滑滚动。

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

在布局管理器中,您需要实现smoothScrollToPosition方法:

    @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.

在这个例子中,我使用名为“calculateCurrentDistanceToPosition”的辅助方法。这可能有点棘手,因为它涉及跟踪当前滚动位置,以及计算给定y位置的滚动位置。您可以在此处找到有关如何跟踪回收器滚动的示例。

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:

计算给定位置的滚动y实际上取决于回收者显示的内容。假设您的所有项目都是相同的高度,您可以通过执行以下计算来计算:

targetScrollY = targetPosition * itemHeight

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

然后,要计算您需要滚动的距离,只需使用目标滚动y减去当前滚动y:

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

2. Slowing down manual scrolling.

2.减慢手动滚动。

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

再一次,您需要编辑布局管理器,这次是scrollVerticallyBy方法:

    @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.

编辑:在上面的方法中,我调用“getScrollState()”。这是RecyclerView的一种方法。在此实现中,我的自定义LayoutManager是我的自定义RecyclerView的嵌套类。如果这对您不起作用,您可以尝试通过某种界面模式获取滚动状态。

3. Slow down the fling speed

3.减慢速度

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

在这里,您希望缩小投掷速度。您需要覆盖RecyclerView子类中的fling方法:

@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.

由于您没有发布任何代码或提供有关您的设置的大量信息,因此我很难提供更具针对性的解决方案,但我希望这涵盖了大多数基础,并将帮助您找到最适合您的解决方案。

#2


28  

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.

通过将0.7替换为您的值来调整速度。

Now use this class in your XML like this.

现在在这样的XML中使用这个类。

<<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.

阅读Java中的RecyclerView。

CustomRecyclerView mRecyclerView;
mRecyclerView = (CustomRecyclerView) findViewById(R.id.my_recycler_view);

#3


17  

Simply implement smoothScrollToPosition() of your LinearLayoutManager:

只需实现LinearLayoutManager的smoothScrollToPosition():

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

};