RecyclerView提供了以下几个api控制RecyclerView滑动
SmoothScrollToPosition(int position) 按一定速度滚动到指定的位置
smoothScrollBy(int dx, int dy) 按一定速度滚动指定的距离
scrollToPosition(int position) 跳转到指定的位置
scrollBy(int dx,int dy) 跳转指定的距离
如果想做出像微信朋友圈双击滚动到顶部的那种效果,则需要使用smoothScrollToPosition(int position)这个方法
如果直接使用的时候,发现滚动速度太慢了,远远没有微信那种效果
那么我们这个时候要怎么修改才能加快滚动的速度呢
我们不妨来看一下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这个方法,那么mLayout是什么呢
由上面两张图可以看出,mLayout就是RecyclerView调用setLayoutManager时传进来的LayoutManager;
我们再看LayoutManager里面的smoothScrollToPosition(int position)方法,此处选择LinearLayoutManager
我们可以看到,此处创建了一个LinearSmoothScroller,然后调用setTargetPosition(position)传进要滑动的位置,最后调用startSmoothScroll(linearSmoothScroller)开始滑动,那么滑动速度是在哪里设置的呢,我们接着看:
首先创建LinearSmoothScroller
可以看到Scroller的构造函数里面获取了MILLISECONDS_PER_PX这个值,再看calculateSpeedPerPixel这个方法,意思就是获取每个px滚动的速度,默认使用25f/displayMetrics.densityDpi计算,所以我们只要通过减少MILLISECONDS_PER_PX这个值就能提高滑动速度了
再看下MILLISECONDS_PER_PX这个值,这个是代表每个px的滚动时间,看下哪个方法用到,如图7所示
calculateTimeForScrolling(int dx)方法有使用,这个方法主要做的工作是把上面算的时间乘以总的滑动距离并返回,同时为了避免当dx非常小时,返回0的情况,做了浮点数向上取整的操作,所以我们还可以在这里通过修改dx或修改返回数值达到减少滑动时间的目的。
回到上面
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
smoothScrollToPosition还剩下这两句代码
setTargetPosition的意思是传进目的位置,以后滑动的时候使用,然后startSmoothScroll(linearSmoothScroller)意思是调用linearSmoothScroller来进行滑动,那么具体的滑动算法就不详细分析了,有兴趣的人可以自己查看源码。
那么根据上面的结论,如果要修改滑动速度,那么新建一个LayoutManager,然后重写SmoothScrollToPosition,然后新建一个Scroller,在Scroller里面的calculateSpeedPerPixel或者calculateTimeForScrolling方法修改对应的参数即可修改成功
直接上代码
public class FastScrollLinearLayoutManager extends LinearLayoutManager {
private float MILLISECONDS_PER_INCH = 0.03f;
private Context mContext;
public FastScrollLinearLayoutManager(Contextcontext) {
super(context);
mContext=context;
setSpeedFast();
}
/**
* 慢滑
*/
public void setSpeedSlow() {
//自己在这里用density去乘,希望不同分辨率设备上滑动速度相同
//0.3f是自己估摸的一个值,可以根据不同需求自己修改
MILLISECONDS_PER_INCH = mContext.getResources().getDisplayMetrics().density * 0.3f;
}
/**
* 快滑,滑动系数自己修改,这里选了一个比较顺眼的数值
*/
public void setSpeedFast() {
MILLISECONDS_PER_INCH=mContext.getResources().getDisplayMetrics().density*0.02f;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
LinearSmoothScrollerlinear SmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
@Nullable
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return FastScrollLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
// 控制滑动速度
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
// 单位速度 25F/densityDpi
// return 1F / displayMetrics.densityDpi;
return MILLISECONDS_PER_INCH / displayMetrics.density;
}
//该方法计算滑动所需时间。在此处间接控制速度。
@Override
protected intcalculateTimeForScrolling(intdx){
/*
控制距离, 然后根据上面那个方(calculateSpeedPerPixel())提供的速度算出时间,
默认一次 滚动 TARGET_SEEK_SCROLL_DISTANCE_PX = 10000个像素,
在此处可以减少该值来达到减少滚动时间的目的.
*/
//间接计算时提高速度,也可以直接在calculateSpeedPerPixel提高
// if (dx > 3000) {
// dx = 3000;
// }
return super.calculateTimeForScrolling(dx);
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}