本文是自己学习这篇文章的总结,
https://mcochin.wordpress.com/2015/05/13/android-customizing-smoothscroller-for-the-recyclerview/ 《ANDROID: CUSTOMIZING SMOOTHSCROLLER FOR THE RECYCLERVIEW》
调用RecyclerView的smoothScrollToPositon可以指定RecyclerView滑动到某个item,但这个滑动的速度很快,如果想要滑动速度可以控制,那么应该怎么办呢?
我们知道在调用RecyclerView的前,应该先为RecyclerView设定一个LayoutManager。举例如下:
mRecyclerView.setLayoutManager(mLinearLayoutManager);
调用mRecyclerView.smoothScrollToPosition
时候,RecyclerView实际调用的是LayoutManager中的代码。从RecyclerView的源码可以看出:
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就是初始化RecyclerView设置的LayoutManager
mLayout.smoothScrollToPosition(this, mState, position);
}
接下来我们可以自定一个LayoutManager,然后复写LayoutManager中的smoothScrollToPosition(this, mState, position)
方法,来达到控制滑动速度的目的。以LinearLayoutManager为例子,代码如下:
/**
* 控制滑动速度的LinearLayoutManager
*/
public class ScrollSpeedLinearLayoutManger extends LinearLayoutManager {
private float MILLISECONDS_PER_INCH = 0.03f;
private Context contxt;
public ScrollSpeedLinearLayoutManger(Context context) {
super(context);
this.contxt = context;
}
@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需要多少毫秒
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
public void setSpeedSlow() {
//自己在这里用density去乘,希望不同分辨率设备上滑动速度相同
//0.3f是自己估摸的一个值,可以根据不同需求自己修改
MILLISECONDS_PER_INCH = contxt.getResources().getDisplayMetrics().density * 0.3f;
}
public void setSpeedFast() {
MILLISECONDS_PER_INCH = contxt.getResources().getDisplayMetrics().density * 0.03f;
}
}
附上LinearLayoutManager中的 smoothScrollToPosition
源码,对比可以看出我们仅仅是覆写了LinearSmoothScroller中的calculateSpeedPerPixel
这个方法而已。
//LinearLayoutManager中源码
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
LinearSmoothScroller linearSmoothScroller =
new LinearSmoothScroller(recyclerView.getContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return LinearLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
核心方法:
//This returns the milliseconds it takes to
//scroll one pixel.
@Override
protected float calculateSpeedPerPixel
(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.density;
//返回滑动一个pixel需要多少毫秒
}
以上就是自己总结,大家也可以去看前言贴出的原文。
顺便介绍下上面涉及的PointF这个类。
/**
* PointF holds two float coordinates
*/
public class PointF implements Parcelable {
public float x;
public float y;
public PointF() {}
public PointF(float x, float y) {
this.x = x;
this.y = y;
}
public PointF(Point p) {
this.x = p.x;
this.y = p.y;
}
//...一些set get 和 Parcelable相关的方法
}
这个是一个坐标类,x,y两点表示坐标位置。
在一些触摸相关的例子中,比较常见。在这里则是用来表示RecyclerView的滑动方向。
//for y: use -1 for up direction, 1 for down direction.
//for x (did not test): use -1 for left direction, 1 for right direction.
举例,从item50滑动到item100,那么此时pointF就是(0,-1)。