RecycleView滑动补充(解决滑动到指定位置顶部的问题)

解决RecycleView滑动到指定位置的问题:


更改前,滑动位置不固定
更改后,滑动位置固定在条目顶部

相信好多人都用过自定义LinearLayoutManager,如下:

import android.content.Context;
import android.graphics.PointF;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;

/**
 * Created by gjl on 2018/3/2.
 */

public class ScrollSpeedLinearLayoutManger extends LinearLayoutManager {
    private float MILLISECONDS_PER_INCH = 0.3f;

    public ScrollSpeedLinearLayoutManger(Context context) {
        super(context);
        //根据不同的屏幕分辨率设置速度
        MILLISECONDS_PER_INCH = context.getResources().getDisplayMetrics().density * 0.1f;
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        LinearSmoothScroller linearSmoothScroller =
                new LinearSmoothScroller(recyclerView.getContext()) {
                    @Override
                    public PointF computeScrollVectorForPosition(int targetPosition) {
                        return ScrollSpeedLinearLayoutManger.this
                                .computeScrollVectorForPosition(targetPosition);
                    }

                    //This returns the milliseconds it takes to
                    //scroll one pixel.
                    @Override
                    protected float calculateSpeedPerPixel
                    (DisplayMetrics displayMetrics) {
                        //返回滑动一个pixel需要多少毫秒
                        return MILLISECONDS_PER_INCH / displayMetrics.density;                      
                    }
                };
        linearSmoothScroller.setTargetPosition(position);
        startSmoothScroll(linearSmoothScroller);
    }
}

使用时:

ScrollSpeedLinearLayoutManger  linearLayoutManger  = new ScrollSpeedLinearLayoutManger(MainActivity.this);
recycleView.setLayoutManager(linearLayoutManger);
//滑动方法
linearLayoutManger.smoothScrollToPosition(recycleView,null,position);

结果发现滑动方法不好用了,使用smoothScrollToPosition时,移动到前面的项时,它默认会将要显示的项底部,但是移动到后面的项时,它默认会将要显示的项顶部,当前移动项在屏幕上显示时,不会移动,用过的应该都有所了解。

解决问题

从上面的代码看到,我们只是设置了LinearSmoothScroller,那么查看一下LinearSmoothScroller的源码发现:

 /**
     * Align child view's left or top with parent view's left or top
     *
     * @see #calculateDtToFit(int, int, int, int, int)
     * @see #calculateDxToMakeVisible(android.view.View, int)
     * @see #calculateDyToMakeVisible(android.view.View, int)
     */
    public static final int SNAP_TO_START = -1;

    /**
     * Align child view's right or bottom with parent view's right or bottom
     *
     * @see #calculateDtToFit(int, int, int, int, int)
     * @see #calculateDxToMakeVisible(android.view.View, int)
     * @see #calculateDyToMakeVisible(android.view.View, int)
     */
    public static final int SNAP_TO_END = 1;

    /**
     * <p>Decides if the child should be snapped from start or end, depending on where it
     * currently is in relation to its parent.</p>
     * <p>For instance, if the view is virtually on the left of RecyclerView, using
     * {@code SNAP_TO_ANY} is the same as using {@code SNAP_TO_START}</p>
     *
     * @see #calculateDtToFit(int, int, int, int, int)
     * @see #calculateDxToMakeVisible(android.view.View, int)
     * @see #calculateDyToMakeVisible(android.view.View, int)
     */
    public static final int SNAP_TO_ANY = 0;

 /**
     * When scrolling towards a child view, this method defines whether we should align the top
     * or the bottom edge of the child with the parent RecyclerView.
     *
     * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector
     * @see #SNAP_TO_START
     * @see #SNAP_TO_END
     * @see #SNAP_TO_ANY
     */
    protected int getVerticalSnapPreference() {
        return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY :
                mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START;
    }

LinearSmoothScroller里面3个状态,这里我们只需要在设置LinearSmoothScroller的时候重写 getVerticalSnapPreference()方法,让滑动位置始终滑动到条目开始位置就好了.

/**
 * Created by gjl on 2018/3/2.
 */

public class ScrollSpeedLinearLayoutManger extends LinearLayoutManager {
    private float MILLISECONDS_PER_INCH = 0.3f;

    public ScrollSpeedLinearLayoutManger(Context context) {
        super(context);
        MILLISECONDS_PER_INCH = context.getResources().getDisplayMetrics().density * 0.1f;
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        LinearSmoothScroller linearSmoothScroller =
                new LinearSmoothScroller(recyclerView.getContext()) {
                    @Override
                    public PointF computeScrollVectorForPosition(int targetPosition) {
                        return ScrollSpeedLinearLayoutManger.this
                                .computeScrollVectorForPosition(targetPosition);
                    }

                    //This returns the milliseconds it takes to
                    //scroll one pixel.
                    @Override
                    protected float calculateSpeedPerPixel
                    (DisplayMetrics displayMetrics) {
                        return MILLISECONDS_PER_INCH / displayMetrics.density;
                        //返回滑动一个pixel需要多少毫秒
                    }
                    
                    //重写这个方法,保证滑动到指定条目的顶部
                    @Override
                    protected int getVerticalSnapPreference() {
                        return SNAP_TO_START;
                    }

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

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。