建立FastScrollLinearLayoutManager,繼承LinearLayoutManager
複寫smoothScrollToPosition()方法,主要複寫LinearSmoothScroller中方法
public class FastScrollLinearLayoutManager extends LinearLayoutManager {
public FastScrollLinearLayoutManager(Context context) {
super(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 FastScrollLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
//該方法控制速度。
//if returned value is 2 ms, it means scrolling 1000 pixels with LinearInterpolation should take 2 seconds.
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
//return 10F / displayMetrics.densityDpi;//可以減少時間,預設25F
return super.calculateSpeedPerPixel(displayMetrics);
}
//該方法計算滑動所需時間。在此處間接控制速度。
//Calculates the time it should take to scroll the given distance (in pixels)
@Override
protected int calculateTimeForScrolling(int dx) {
//間接計算時提高速度,也可以直接在calculateSpeedPerPixel提高
if (dx > 3000) {
dx = 3000;
}
int time = super.calculateTimeForScrolling(dx);
LogUtil.d(time);//列印時間看下
return time;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
從複寫的兩個方法可以看出,都是為了提高滑動速度。一種是直接修改速度,另外一種是通過減少距離來減少所需時間,間接提高滑動速度。
RecyclerView 滑動過程梳理
調用RecyclerView.smoothScrollToPosition(position)時
`public void smoothScrollToPosition(int position) {
//...直接調用了LayoutManager的該方法
mLayout.smoothScrollToPosition(this, mState, position);
}`
LinearLayoutManager中
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,int position) {
LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
//...
};
//設定終點位置
linearSmoothScroller.setTargetPosition(position);
//開始滾動,使用LinearSmoothScroller(一直勻速滑動,當targetPosition出現在螢幕上時再減速滑動),startSmoothScroll()是LayoutManager中的方法
startSmoothScroll(linearSmoothScroller);
}
LayoutManager中
public void startSmoothScroll(SmoothScroller smoothScroller) {
//...
mSmoothScroller = smoothScroller;
//調用SmoothScroller.start()方法開始滾動,this參數指目前LayoutManager
mSmoothScroller.start(mRecyclerView, this);
}
SmoothScroller中
void start(RecyclerView recyclerView, LayoutManager layoutManager) {
//...
//使用ViewFlinger進行動畫,ViewFlinger實作了Runnable接口,并且内部使用了Scroller,這樣就可以post自己進而對RecyclerView不斷layout就可以實作滑動
mRecyclerView.mViewFlinger.postOnAnimation();
}
ViewFlinger中,這是實作滑動的重點,省略了很多代碼邏輯
private class ViewFlinger implements Runnable {
@Override
public void run() {
if (scroller.computeScrollOffset()) {
//調用SmoothScroller的onAnimation方法
smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY);
}
}
}
SmoothScroller中
private void onAnimation(int dx, int dy) {
//...
if (mTargetView != null) {
// verify target position
if (getChildPosition(mTargetView) == mTargetPosition) {
//要滑動到的位置已經顯示在螢幕上,onTargetFound()方法裡update了內插補點器,由線性內插補點器變成了減速的內插補點器。
onTargetFound(mTargetView, recyclerView.mState, mRecyclingAction);
mRecyclingAction.runIfNecessary(recyclerView);
}
//...
if (mRunning) {
//再下一次滑動
onSeekTargetStep(dx, dy, recyclerView.mState, mRecyclingAction);
//調用内部類Action的runIfNecessary方法
mRecyclingAction.runIfNecessary(recyclerView);
}
}
Action中
private void runIfNecessary(RecyclerView recyclerView) {
//調用了ViewFlinger.smoothScrollBy()方法,并傳入了mDuration,mDuration是在SmoothScroller中upDate()時傳入的,就是由前文講的兩個方法共同決定的
recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration, mInterpolator);
}
ViewFlinger中開始滾動
public void smoothScrollBy(int dx, int dy, int duration, Interpolator interpolator) {
if (mInterpolator != interpolator) {
mInterpolator = interpolator;
mScroller = ScrollerCompat.create(getContext(), interpolator);
}
setScrollState(SCROLL_STATE_SETTLING);
mLastFlingX = mLastFlingY = 0;
//調用Scroller開始滾動,此處即duration
mScroller.startScroll(0, 0, dx, dy, duration);
postOnAnimation();
}
這塊粗略的按照流程說了一下滾動過程,涉及的類比較多,最終通過Scroller來進行滾動。