Android開發:RecyclerView平滑流暢的滑動到指定位置

MichaelX發表於2019-03-04

背景

在專案中,想使RecyclerView慢慢的平緩滑動指定位置,於是使用:

RecyclerView.smoothScrollToPosition(int);複製程式碼

發現效果並不理想,滑動過程很突兀,很快就滑動到了指定位置,並沒有像函式名那樣smooth(流暢的,平滑的),也就是說smoothScrollToPosition沒有滑動效果,黑人問號???

本文原創作者MichaelX,掘金鍊接:https://juejin.im/user/56efe6461ea493005565dafd,轉載請註明出處。複製程式碼

探索歷程

既然函式名是流暢平緩的滑動到指定位置,為什麼並不理想呢?檢視原始碼如下:

 public void smoothScrollToPosition(int position) {
        // ···省略無關程式碼,mLayout是該RecyclerView的LayoutManager物件
        mLayout.smoothScrollToPosition(this, mState, position);
    }複製程式碼

所以實際上是呼叫RecyclerView.LayoutManager.smoothScrollToPosition()方法,這是個抽象方法。由於筆者專案中是LinearLayoutManager於是找到其具體實現如下:

 @Override
        public void smoothScrollToPosition(RecyclerView recyclerView,
                                           RecyclerView.State state, final int position) {

            LinearSmoothScroller smoothScroller = new LinearSmoothScroller(context);

            smoothScroller.setTargetPosition(position);
            startSmoothScroll(smoothScroller);
        }複製程式碼

生成一個RecyclerView.SmoothScroller的子類LinearSmoothScroller物件smoothScroller,接著利用smoothScroller去完成剩下的滑動工作。

於是進去LinearSmoothScroller看看。重大發現—裡面有一個跟滑動速度相關的函式:

    /**
     * Calculates the scroll speed.
     * 計算滑動速度
     * 返回:滑過1px所需的時間消耗。
     */
    protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
        // MILLISECONDS_PER_INCH是常量,等於20f
        return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
    }複製程式碼

既然RecyclerView.smoothScrollToPosition(int);很快,是不是延長其滑動時間就可以呢?

解決smoothScrollToPosition無效

為了驗證上節延長滑動時間的想法,自定義一個LinearLayoutManager:

public class SmoothScrollLayoutManager extends LinearLayoutManager {

        public SmoothScrollLayoutManager(Context context) {
            super(context);
        }

        @Override
        public void smoothScrollToPosition(RecyclerView recyclerView,
                                           RecyclerView.State state, final int position) {

            LinearSmoothScroller smoothScroller =
                    new LinearSmoothScroller(recyclerView.getContext()) {
                        // 返回:滑過1px時經歷的時間(ms)。
                        @Override
                        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                            return 150f / displayMetrics.densityDpi;
                        }
                    };

            smoothScroller.setTargetPosition(position);
            startSmoothScroll(smoothScroller);
        }
    }複製程式碼

Binggo!成功!呼叫RecyclerView.smoothScrollToPosition(int);發現滑動速度變慢很多,不再突兀,不再突然滑過去,沒有任何過渡,而是緩慢滑過去,終於名副其實的smooth

本文原創作者MichaelX,掘金鍊接:https://juejin.im/user/56efe6461ea493005565dafd,轉載請註明出處。複製程式碼

結語

通過自定義LinearLayoutManager,重寫smoothScrollToPosition()方法中LinearSmoothScroller物件的calculateSpeedPerPixel(DisplayMetrics)方法,可以使RecyclerView.smoothScrollToPosition(int);平滑的流暢的滑動到指定位置。其他LayoutManager暫時沒用到,需要讀者自己嘗試。

如果讀者朋友們有其他的辦法,歡迎留言交流。

相關文章