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

RecyclerView提供了以下幾個(gè)api控制RecyclerView滑動(dòng)

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

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

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

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

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

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

那么我們這個(gè)時(shí)候要怎么修改才能加快滾動(dòng)的速度呢

我們不妨來看一下smoothScrollToPosition這個(gè)方法的源碼

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這個(gè)方法,那么mLayout是什么呢


1
2

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

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


3

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

首先創(chuàng)建LinearSmoothScroller

4


5


6

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

7

再看下MILLISECONDS_PER_PX這個(gè)值,這個(gè)是代表每個(gè)px的滾動(dòng)時(shí)間,看下哪個(gè)方法用到,如圖7所示

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

回到上面

linearSmoothScroller.setTargetPosition(position);

startSmoothScroll(linearSmoothScroller);

smoothScrollToPosition還剩下這兩句代碼

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

那么根據(jù)上面的結(jié)論,如果要修改滑動(dòng)速度,那么新建一個(gè)LayoutManager,然后重寫SmoothScrollToPosition,然后新建一個(gè)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è)備上滑動(dòng)速度相同

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

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

????????}


????/**

? ? ???? * 快滑,滑動(dòng)系數(shù)自己修改,這里選了一個(gè)比較順眼的數(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);

????????}

????????// 控制滑動(dòng)速度

????????@Override

????????protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {

????????????// 單位速度 25F/densityDpi

????????????// return 1F / displayMetrics.densityDpi;

????????????return MILLISECONDS_PER_INCH / displayMetrics.density;

????????}

????????//該方法計(jì)算滑動(dòng)所需時(shí)間。在此處間接控制速度。

????????@Override

????????protected intcalculateTimeForScrolling(intdx){

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

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

? ? ? ? ? ? ? ? ? 默認(rèn)一次 滾動(dòng) TARGET_SEEK_SCROLL_DISTANCE_PX = 10000個(gè)像素,

? ? ? ? ? ? ? ? ? 在此處可以減少該值來達(dá)到減少滾動(dòng)時(shí)間的目的.

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

????????????//間接計(jì)算時(shí)提高速度,也可以直接在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輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

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

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