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是什么呢


由上面兩張圖可以看出,mLayout就是RecyclerView調(diào)用setLayoutManager時傳進來的LayoutManager;
我們再看LayoutManager里面的smoothScrollToPosition(int position)方法,此處選擇LinearLayoutManager

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



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

再看下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);
????}
}