RecyclerView 平滑滾動可控制滾動速度的終極解決方案
原創 2017-08-09 認真的 小蘇
recyclerview 滑動到指定位置有好多坑,相信用過的人都遇到坑了,沒辦法遇到坑了,也要把它填上,今天遇到一個問題,要求 : recyclerview 平滑的滾動到指定位置並且位於螢幕中間,而且速度不能太快了。。。
看下實現效果圖吧,仿騰訊新聞視訊列表的滑動效果。
程式碼
recyclerview 常用的位置跳轉
((LinearLayoutManager) rl_video.getLayoutManager()).scrollToPositionWithOffset(itemPosition, 20);
rl_video.scrollToPosition(itemPosition);
rl_video.smoothScrollBy(0, top);
rl_video.smoothScrollToPosition(position);
這些跳轉有好多蛋疼的問題,不是跳到指定位置,要不就是滑動到指定位置不準確,要不就是滑動太快,反正就是達不到要求。
於是Google了半天,終於在stackoverflow 找到了解決思路。
看下面解決程式碼:
public class ScrollSpeedLinearLayoutManger extends LinearLayoutManager {
public ScrollSpeedLinearLayoutManger(Context context) {
super(context, VERTICAL, false);
}
public ScrollSpeedLinearLayoutManger(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
Log.e("linksu",
"smoothScrollToPosition(ScrollSpeedLinearLayoutManger.java:62)");
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class CenterSmoothScroller extends LinearSmoothScroller {
CenterSmoothScroller(Context context) {
super(context);
}
@Nullable
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return ScrollSpeedLinearLayoutManger.this.computeScrollVectorForPosition(targetPosition);
}
@Override
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 0.2f;
}
@Override
protected int getVerticalSnapPreference() {
return SNAP_TO_START;
}
}
}
重寫 LinearLayoutManager,為什麼要重寫呢,因為我是呼叫這個方法進行滑動的 rl_video.smoothScrollToPosition(position); 看下這個方法的原始碼是如何寫的
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);
}
如上程式碼所示,知其然不知其所以然,正是呼叫了LinearLayoutManager 中的 smoothScrollToPosition。
實現的核心程式碼
private class CenterSmoothScroller extends LinearSmoothScroller {
CenterSmoothScroller(Context context) {
super(context);
}
@Nullable
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return ScrollSpeedLinearLayoutManger.this.computeScrollVectorForPosition(targetPosition);
}
@Override
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 0.2f;
}
@Override
protected int getVerticalSnapPreference() {
return SNAP_TO_START;
}
}
calculateDtToFit 方法是控制滑動的位置,可以在這個方法中所以的控制滑動的位置
@Override
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
calculateSpeedPerPixel 方法是控制滑動速度的
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return 0.2f;
}
核心的主要是這兩個方法。
呼叫方式:這樣就很簡單的實現了
layoutManager = new ScrollSpeedLinearLayoutManger(this);
rl_video.setLayoutManager(layoutManager);
rl_video.smoothScrollToPosition(position);
另一種更簡單的方案
RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(context) {
@Override protected int getVerticalSnapPreference() {
return LinearSmoothScroller.SNAP_TO_START;
}};
現在設定要滾動到的位置:
smoothScroller.setTargetPosition(position);
並將SmoothScroller傳遞給LayoutManager:
layoutManager.startSmoothScroll(smoothScroller);
LinearSmoothScroller extends RecyclerView.SmoothScroller 解決思路其實是一樣的。
RecyclerView滑動速度的設定(此處以橫向的滑動為例)
自定義一個類繼承自LayoutManager,然後過載其scrollHorizontallyBy()方法,其中在該方法中,第一個引數dx即為滑動的距>
離,因此改變這個值就可以改變滑動的速度。為了方便設定其滑動的速度,可以自定義一個速度因子speedRatio,通過利用> > > dx*speedRatio來達到控制速度的目的。示例程式碼如下:
public class CustomSGLayoutManager extends StaggeredGridLayoutManager {
private double speedRatio;
public CustomSGLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public CustomSGLayoutManager(int spanCount, int orientation) {
super(spanCount, orientation);
}
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
int a = super.scrollHorizontallyBy((int)(speedRatio*dx), recycler, state);//遮蔽之後無滑動效果,證明滑動的效果就是由這個函式實現
if(a == (int)(speedRatio*dx)){
return dx;
}
return a;
}
public void setSpeedRatio(double speedRatio){
this.speedRatio = speedRatio;
}
}
而後,例項化這個類,並設定為RecyclerView的佈局,程式碼如下所示
private RecyclerView skyRecyclerView;
public void doSomething(){
CustomSGLayoutManager skyLayoutManager = new CustomSGLayoutManager(1,StaggeredGridLayoutManager.HORIZONTAL);//例項化自定義類
skyLayoutManager.setSpeedRatio(0.82);//設定其速度因子
skyRecyclerView.setLayoutManager(skyLayoutManager);
}
RecyclerView拋擲速度的設定(此處以橫向的滑動為例)
自定義一個類繼承自RecyclerView,然後過載其fling()方法,在該方法中velocityX為其橫向的移動距離,velocityY為其縱向的移動距離(此處以橫向的滑動為例),改變這兩個引數,即可以改變其相應方向滑動的距離。為了方便設定,這裡同樣引入一個縮放因子scale,程式碼示例如下:
public class CustomRecyclerView extends RecyclerView {
private double scale; //拋擲速度的縮放因子
public CustomRecyclerView(Context context) {
super(context);
}
public CustomRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setflingScale(double scale){
this.scale = scale;
}
@Override
public boolean fling(int velocityX, int velocityY) {
velocityX *= scale;
return super.fling(velocityX, velocityY);
}
}
而後,在RecyclerView中設定其縮放因子即可,程式碼如下:
skyLayoutManager.setSpeedRatio(0.5);
視訊列表滾動連播技術探究系列。
1、仿網易/QQ空間視訊列表滾動連播炫酷效果(V1.0 挖坑之路)。
2、仿網易/QQ空間視訊列表滾動連播炫酷效果(V2.0 填坑之路) 。
3、仿網易視訊列表滾動連播炫酷效果(v3.0 穩定版-思想改變及優化) 穩定版-進行優化和思想上的改變。
4、RecyclerView 平滑滾動可控制滾動速度的終極解決方案。
5、仿網易視訊列表連播炫酷效果 - v3.1 升級版-細節優化(網路狀態切換、item點選事件等)。
持續更新中.....
相關文章
- RecyclerView滾動位置,滾動速度設定View
- 移動端滾動穿透解決方案穿透
- 遇到overflow: scroll不能平滑滾動怎麼解決?
- 移動端滾動穿透問題解決方案穿透
- 移動端滾動穿透問題完美解決方案穿透
- 多層 UIScrollView 巢狀滾動解決方案UIView巢狀
- 瀏覽器原生支援平滑滾動瀏覽器
- Flutter 滾動控制元件篇-->滾動監聽及控制(ScrollController)Flutter控制元件Controller
- 解決移動端滾動穿透穿透
- 【前端詞典】滾動穿透問題的解決方案前端穿透
- 基於 RecyclerView 實現的歌詞滾動自定義控制元件View控制元件
- 解決方案 | IrfanView如何滑動滾輪影像縮放?View
- 使用jQuery實現的平滑滾動輪播圖jQuery
- Qt列表等控制元件實現平滑滾動&deepin啟動器存在的問題QT控制元件
- 移動端滾動穿透是什麼原因?有哪些解決方案?穿透
- ScrollView(RecyclerView等)為什麼會自動滾動原理分析,還有阻止自動滑動的解決方View
- 移動端頁面滾動--解決方法
- 如何在 pyqt 中使用動畫實現平滑滾動的 QScrollAreaQT動畫
- 使用js控制滾動條的位置JS
- 縱向控制的橫向滾動
- Smooze for Mac(滑鼠平滑滾動神器)1.9.26漢化版Mac
- Flutter可滾動Widgets-ListViewFlutterView
- pod install / pod update 速度慢的終極解決方案
- 詳解移動端網頁設計實現內滾動的四種解決方案網頁
- div滾動條樣式,水平滾動
- 隱藏滾動條保留滾動效果
- 解決集合檢視的header遮住滾動條Header
- 短視訊程式開發,RecyclerView自帶的滾動條View
- 直播平臺原始碼,迴圈滾動RecyclerView的實現原始碼View
- Flutter 滾動控制元件篇-->ListViewFlutter控制元件View
- CSS 滾動驅動動畫終於正式支援了CSS動畫
- 解決移動裝置上iframe滾動條的問題
- 直播軟體原始碼,自定義RecyclerView支援快速滾動原始碼View
- css隱藏滾動條並可以滾動CSS
- 移動端div跟隨滾動條滾動(自制
- 彈層蒙版(mask),ios滾動穿透,我們專案的解決方案iOS穿透
- 你不能不知道的Flutter:Flutter影片滾動播放解決方案Flutter
- CSS題目系列(1) - 可滾動的TableCSS
- mac滑鼠平滑滾動工具:Mac Mouse Fix for Mac中文版Mac