RecyclerView快速滑動到頂部(源碼分析)

RecyclerView提供了以下幾個api控制RecyclerView滑動

SmoothScrollToPosition(int position) 按一定速度滾動到指定的位置

smoothScrollBy(int dx, int dy)? ?按一定速度滾動指定的距離

scrollToPosition(int position)? ?跳轉(zhuǎn)到指定的位置

scrollBy(int dx,int dy)? ? 跳轉(zhuǎn)指定的距離

如果想做出像微信朋友圈雙擊滾動到頂部的那種效果,則需要使用smoothScrollToPosition(int position)這個方法

如果直接使用的時候,發(fā)現(xiàn)滾動速度太慢了,遠遠沒有微信那種效果

那么我們這個時候要怎么修改才能加快滾動的速度呢

我們不妨來看一下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調(diào)用了smoothScrollToPosition這個方法,那么mLayout是什么呢


1
2

由上面兩張圖可以看出,mLayout就是RecyclerView調(diào)用setLayoutManager時傳進來的LayoutManager;

我們再看LayoutManager里面的smoothScrollToPosition(int position)方法,此處選擇LinearLayoutManager


3

我們可以看到,此處創(chuàng)建了一個LinearSmoothScroller,然后調(diào)用setTargetPosition(position)傳進要滑動的位置,最后調(diào)用startSmoothScroll(linearSmoothScroller)開始滑動,那么滑動速度是在哪里設(shè)置的呢,我們接著看:

首先創(chuàng)建LinearSmoothScroller

4


5


6

可以看到Scroller的構(gòu)造函數(shù)里面獲取了MILLISECONDS_PER_PX這個值,再看calculateSpeedPerPixel這個方法,意思就是獲取每個px滾動的速度,默認使用25f/displayMetrics.densityDpi計算,所以我們只要通過減少MILLISECONDS_PER_PX這個值就能提高滑動速度了

7

再看下MILLISECONDS_PER_PX這個值,這個是代表每個px的滾動時間,看下哪個方法用到,如圖7所示

calculateTimeForScrolling(int dx)方法有使用,這個方法主要做的工作是把上面算的時間乘以總的滑動距離并返回,同時為了避免當dx非常小時,返回0的情況,做了浮點數(shù)向上取整的操作,所以我們還可以在這里通過修改dx或修改返回數(shù)值達到減少滑動時間的目的。

回到上面

linearSmoothScroller.setTargetPosition(position);

startSmoothScroll(linearSmoothScroller);

smoothScrollToPosition還剩下這兩句代碼

setTargetPosition的意思是傳進目的位置,以后滑動的時候使用,然后startSmoothScroll(linearSmoothScroller)意思是調(diào)用linearSmoothScroller來進行滑動,那么具體的滑動算法就不詳細分析了,有興趣的人可以自己查看源碼。

那么根據(jù)上面的結(jié)論,如果要修改滑動速度,那么新建一個LayoutManager,然后重寫SmoothScrollToPosition,然后新建一個Scroller,在Scroller里面的calculateSpeedPerPixel或者calculateTimeForScrolling方法修改對應(yīng)的參數(shù)即可修改成功

直接上代碼

????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去乘,希望不同分辨率設(shè)備上滑動速度相同

????????//0.3f是自己估摸的一個值,可以根據(jù)不同需求自己修改

????????MILLISECONDS_PER_INCH = mContext.getResources().getDisplayMetrics().density * 0.3f;

????????}


????/**

? ? ???? * 快滑,滑動系數(shù)自己修改,這里選了一個比較順眼的數(shù)值

? ? ???? */

????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){

????????????/*

? ? ? ? ? ? ? ? ? 控制距離, 然后根據(jù)上面那個方(calculateSpeedPerPixel())提供的速度算出時間,

? ? ? ? ? ? ? ? ? 默認一次 滾動 TARGET_SEEK_SCROLL_DISTANCE_PX = 10000個像素,

? ? ? ? ? ? ? ? ? 在此處可以減少該值來達到減少滾動時間的目的.

? ? ? ? ? ? ? ????? */

????????????//間接計算時提高速度,也可以直接在calculateSpeedPerPixel提高

????????????//? ? ? ? ? ? ? ? if (dx > 3000) {

????????????//? ? ? ? ? ? ? ? ? ? dx = 3000;

????????????//? ? ? ? ? ? ? ? }

????????????????return super.calculateTimeForScrolling(dx);

????????}

????};

????linearSmoothScroller.setTargetPosition(position);

????startSmoothScroll(linearSmoothScroller);

????}

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容