android 快速 顶部,Android RecyclerView 快速滑到顶部
前言:
使用RecyclerView時,調用smoothScrollToPostion()方法滑動到指定位置,但是條目很多時滑動的很慢,本篇文章就是實現RecyclerView的快速滑動。
先介紹如何實現,然后再介紹原理。
1. 實現代碼
創建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) {
/*
控制單位速度, 毫秒/像素, 滑動1像素需要多少毫秒.
默認為 (25F/densityDpi) 毫秒/像素
mdpi上, 1英寸有160個像素點, 25/160,
xxhdpi,1英寸有480個像素點, 25/480,
*/
//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())提供的速度算出時間,
默認一次 滾動 TARGET_SEEK_SCROLL_DISTANCE_PX = 10000個像素,
在此處可以減少該值來達到減少滾動時間的目的.
*/
//間接計算時提高速度,也可以直接在calculateSpeedPerPixel提高
if (dx > 3000) {
dx = 3000;
}
int time = super.calculateTimeForScrolling(dx);
LogUtil.d(time);//打印時間看下
return time;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}復制代碼
從復寫的兩個方法可以看出,都是為了提高滑動速度。一種是直接修改速度,另外一種是通過減少距離來減少所需時間,間接提高滑動速度。
這兩種方法都可以,看自己所需。接下來就講講實現的原理。這塊我只是梳理的大致的流程,不過至此你已經可以實現快速滑動了。
2. RecyclerView 滑動過程梳理
1.調用RecyclerView.smoothScrollToPosition(position)時
public void smoothScrollToPosition(int position) {
//...直接調用了LayoutManager的該方法
mLayout.smoothScrollToPosition(this, mState, position);
}復制代碼
2.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);
}復制代碼
3.LayoutManager中
public void startSmoothScroll(SmoothScroller smoothScroller) {
//...
mSmoothScroller = smoothScroller;
//調用SmoothScroller.start()方法開始滾動,this參數指當前LayoutManager
mSmoothScroller.start(mRecyclerView, this);
}復制代碼
4.SmoothScroller中
void start(RecyclerView recyclerView, LayoutManager layoutManager) {
//...
//使用ViewFlinger進行動畫,ViewFlinger實現了Runnable接口,并且內部使用了Scroller,這樣就可以post自己進而對RecyclerView不斷layout就可以實現滑動
mRecyclerView.mViewFlinger.postOnAnimation();
}復制代碼
5.ViewFlinger中,這是實現滑動的重點,省略了很多代碼邏輯
private class ViewFlinger implements Runnable {
@Override
public void run() {
if (scroller.computeScrollOffset()) {
//調用SmoothScroller的onAnimation方法
smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY);
}
}
}復制代碼
6.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);
}
}復制代碼
7.Action中
private void runIfNecessary(RecyclerView recyclerView) {
//調用了ViewFlinger.smoothScrollBy()方法,并傳入了mDuration,mDuration是在SmoothScroller中upDate()時傳入的,就是由前文講的兩個方法共同決定的
recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration, mInterpolator);
}復制代碼
8.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來進行滾動。
結語:
本篇文章實現了RecyclerView的快速滾動,但需要注意一個問題:如果你的Item比較復雜,滾動起來會卡頓。 這個在看源碼時的一個注釋里面有提到,后來實踐時確實也發現。不得不說微信朋友圈滑動起來的真的快,它用的是ListView,貌似開啟了FastEnable屬性。
同時也可以仿照知乎,先使用RecyclerView.scrollToPosition(position)直接滑動到某一個位置后再使用smoothScrollToPosition(0)滑動到頂部。這塊在RecyclerView里的Action類中jumpTo()的注釋里有提到,如果很遠的話可以先到一個位置后再滑動。
這兩種滑動到頂部的方式都實現了一個小Demo。測試代碼在GitHub上 FastScrollFragment 。
另外在自己寫的小項目上也用上了 ZhihuDaily,可以查看這兩個Demo來具體了解。
總結
以上是生活随笔為你收集整理的android 快速 顶部,Android RecyclerView 快速滑到顶部的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android webservices
- 下一篇: html中after伪类原理,css伪类