Android进阶八:RecyclerView自动滚动

来源:互联网 发布:软件机器码修改 编辑:程序博客网 时间:2024/05/16 23:45

smoothScrollToPosition()

在使用RecyclerView的时候,有一些场景需要RecyclerView能自动滑动到指定的item,这种情况可以调用RecyclerView的以下方法来实现:

scrollToPosition(int position)smoothScrollToPosition(int position)

这两个方法传入需要滑动到的item的position就可以实现跳转到相应的item,区别是scrollToPosition()会立即跳转到相应item,不会有滑动的效果,smoothScrollToPosition()跳转的同时,会有滑动的效果,但是滑动速度很快,用户体验效果不好,如何能控制速度达到一个好的效果呢?

先来看下smoothScrollToPosition()的源码:

    public void smoothScrollToPosition(int position) {        if (mLayoutFrozen) {            return;        }        if (mLayout == null) {            Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " +                    "Call setLayoutManager with a non-null argument.");            return;        }        mLayout.smoothScrollToPosition(this, mState, position);    }

它最终是调用了mLayout.smoothScrollToPosition(this, mState, position),mLayout是RecyclerView的布局管理器,比如线性布局管理器LinearLayoutManager:

mRecyclerView.setLayoutManager(mLinearLayoutManager); 

来看下smoothScrollToPosition()在线性布局管理器中的实现:

    @Override    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,            int position) {        LinearSmoothScroller linearSmoothScroller =                new LinearSmoothScroller(recyclerView.getContext());        linearSmoothScroller.setTargetPosition(position);        startSmoothScroll(linearSmoothScroller);    }

使用的是LinearSmoothScroller进行滑动操作,再来看LinearSmoothScroller类,它有一个获取滑动速度的方法:

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

所以我们可以想办法重写这个方法来改变RecyclerView滑动的速度。

我们自定义一个LinearLayoutManager:

public class ScrollLinearLayoutManager extends LinearLayoutManager {    private static final float MILLISECONDS_PER_INCH = 25f;    public ScrollLinearLayoutManager(Context context) {        super(context);    }    @Override    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, final int position) {        LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext())        {            @Nullable            @Override            public PointF computeScrollVectorForPosition(int targetPosition) {                return ScrollLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);            }            @Override            protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {                return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;            }        };        linearSmoothScroller.setTargetPosition(position);        startSmoothScroll(linearSmoothScroller);    }}

重写smoothScrollToPosition()方法,然后重新实例化一个LinearSmoothScroller,并重写calculateSpeedPerPixel()方法,
这样,可以调整MILLISECONDS_PER_INCH的值,来实现RecyclerView滑动速度的调整。

补充

由当前item到目标item的中间要滑动的item数量可能每次都不一样,这样固定的移动速度也会导致用户体验不好,所以可以根据需要滑动的item数量来动态的调整滑动速度,
我们再修改下calculateSpeedPerPixel():

 protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {                View view = getChildAt(0);                if(view != null) {                    final int firstChildPos = getPosition(getChildAt(0)); //获取当前item的position                    int delta = Math.abs(position - firstChildPos);//算出需要滑动的item数量                    if(delta == 0)                        delta = 1;                    return (MILLISECONDS_PER_INCH/delta) / displayMetrics.densityDpi;                }                else                {                    return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;                }            }

这样当需要滑动的item数量越多,滑动速度越快,item数量少时,滑动会较慢,这样就会有一个好的用户体验。

原创粉丝点击