RecyclerView smoothScrollToPosition的滾動時間

當RecyclerView中的數據集很大時,通過smoothScrollToPosition去滾動到一個位置,如果這個位置和當前位置相差很遠,比如說300項,你會發現整個過程很長,比如說我遇到的,滾動300項,用了3.5秒。

這主要跟RecyclerView smoothScroll的方式有關,它內部有一個常量值代表每滾動1px需要多少時間,所以滾動的距離越遠,需要的時間越長。所以當真的需要滾動很多項時,有時看着真心蛋疼,所以就想看看怎麼改一下。

看下LinearLayoutmanager.smoothScrollToPosition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
        int position) {
    LinearSmoothScroller linearSmoothScroller =
            new LinearSmoothScroller(recyclerView.getContext()) {
                @Override
                public PointF computeScrollVectorForPosition(int targetPosition) {
                    return LinearLayoutManager.this
                            .computeScrollVectorForPosition(targetPosition);
                }
            };
    linearSmoothScroller.setTargetPosition(position);
    startSmoothScroll(linearSmoothScroller);
}

內部是實例化了一個LinearSmoothScroller的實例來處理Scroll事件的,我們自字義一個LinearSmoothScroller應該就能自定義Smooth事件,上面的computeScrollVectorForPosition方法不用管,直接複製過來就行了,因爲LinearSmoothScroller是抽象類,這個方法必須實現。

然後看下LinearSmoothScroller 的方法,發現一個方法叫protected int calculateTimeForScrolling(int dx),看這名字就知道函數的作用了,直接重寫這個函數,讓它最多返回1500:

1
2
3
4
@Override
protected int calculateTimeForScrolling(int dx) {
    return Math.min(1500, super.calculateTimeForScrolling(dx));
}

但是,實際滾動時間更長了。。打Log,把每次返回值和dx的值都打印出來,然後繼續測試,然後發現這個函數不是計算這一個smoothScrollToPosition需要的時間的,實際情況時,當實際需要滾動的距離大於10000時,滾動會分多次進行,比如說滾動52000距離,實際會這個函數會調用6次,dx的值前5次是10000,最後一次是2000。實際滾動時間是這6次返回值的和。

知道了這個,解決也簡單了,它想分多次調用就讓它多次調用吧,我只要每次返回的時間值很小就行了。方法有兩個。

  • 直接修改返回值,讓它足夠小
  • 修改傳入的參數,當dx足夠小時,計算出的時間自然就小了。

我決定採用第二種方法,當滾動距離比較小時不會造成影響,完整代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) {
    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        LinearSmoothScroller linearSmoothScroller =
                new LinearSmoothScroller(recyclerView.getContext()) {
                    @Override
                    protected int calculateTimeForScrolling(int dx) {
                        // 此函數計算滾動dx的距離需要多久,當要滾動的距離很大時,比如說52000,
                        // 經測試,系統會多次調用此函數,每10000距離調一次,所以總的滾動時間
                        // 是多次調用此函數返回的時間的和,所以修改每次調用該函數時返回的時間的
                        // 大小就可以影響滾動需要的總時間,可以直接修改些函數的返回值,也可以修改
                        // dx的值,這裏暫定使用後者.
                        // (See LinearSmoothScroller.TARGET_SEEK_SCROLL_DISTANCE_PX)
                        if (dx > 3000) {
                            dx = 3000;
                        }
                        return super.calculateTimeForScrolling(dx);
                    }

                    @Override
                    public PointF computeScrollVectorForPosition(int targetPosition) {
                        return mLayoutManager.computeScrollVectorForPosition(targetPosition);
                    }
                };
        linearSmoothScroller.setTargetPosition(position);
        startSmoothScroll(linearSmoothScroller);
    }
};


原文鏈接:http://www.angeldevil.me/2015/09/08/The-smoothScrollToPosition-duration-of-RecyclerView/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章