當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/