Android RecyclerView 實現快速滑動
前言:
使用RecyclerView時,呼叫smoothScrollToPostion()方法滑動到指定位置,但是條目很多時滑動的很慢,本篇文章就是實現RecyclerView的快速滑動。
先介紹如何實現,然後再介紹原理。
1. 實現程式碼
- 建立FastScrollLinearLayoutManager,繼承LinearLayoutManager
- 複寫smoothScrollToPosition()方法,主要複寫LinearSmoothScroller中方法
程式碼如下,解釋全在註釋中:
public class FastScrollLinearLayoutManager extends LinearLayoutManager {
public FastScrollLinearLayoutManager(Context context) {
super(context);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return FastScrollLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
//該方法控制速度。
//if returned value is 2 ms, it means scrolling 1000 pixels with LinearInterpolation should take 2 seconds.
@Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
/*
控制單位速度, 毫秒/畫素, 滑動1畫素需要多少毫秒.
預設為 (25F/densityDpi) 毫秒/畫素
mdpi上, 1英寸有160個畫素點, 25/160,
xxhdpi,1英寸有480個畫素點, 25/480,
*/
//return 10F / displayMetrics.densityDpi;//可以減少時間,預設25F
return super.calculateSpeedPerPixel(displayMetrics);
}
//該方法計算滑動所需時間。在此處間接控制速度。
//Calculates the time it should take to scroll the given distance (in pixels)
@Override
protected int calculateTimeForScrolling(int dx) {
/*
控制距離, 然後根據上面那個方(calculateSpeedPerPixel())提供的速度算出時間,
預設一次 滾動 TARGET_SEEK_SCROLL_DISTANCE_PX = 10000個畫素,
在此處可以減少該值來達到減少滾動時間的目的.
*/
//間接計算時提高速度,也可以直接在calculateSpeedPerPixel提高
if (dx > 3000) {
dx = 3000;
}
int time = super.calculateTimeForScrolling(dx);
LogUtil.d(time);//列印時間看下
return time;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
從複寫的兩個方法可以看出,都是為了提高滑動速度。一種是直接修改速度,另外一種是通過減少距離來減少所需時間,間接提高滑動速度。
這兩種方法都可以,看自己所需。接下來就講講實現的原理。這塊我只是梳理的大致的流程,不過至此你已經可以實現快速滑動了。
2. RecyclerView 滑動過程梳理
1.呼叫RecyclerView.smoothScrollToPosition(position)時
public void smoothScrollToPosition(int position) {
//...直接呼叫了LayoutManager的該方法
mLayout.smoothScrollToPosition(this, mState, position);
}
2.LinearLayoutManager中
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
//...
};
//設定終點位置
linearSmoothScroller.setTargetPosition(position);
//開始滾動,使用LinearSmoothScroller(一直勻速滑動,當targetPosition出現在螢幕上時再減速滑動),startSmoothScroll()是LayoutManager中的方法
startSmoothScroll(linearSmoothScroller);
}
3.LayoutManager中
public void startSmoothScroll(SmoothScroller smoothScroller) {
//...
mSmoothScroller = smoothScroller;
//呼叫SmoothScroller.start()方法開始滾動,this引數指當前LayoutManager
mSmoothScroller.start(mRecyclerView, this);
}
4.SmoothScroller中
void start(RecyclerView recyclerView, LayoutManager layoutManager) {
//...
//使用ViewFlinger進行動畫,ViewFlinger實現了Runnable介面,並且內部使用了Scroller,這樣就可以post自己進而對RecyclerView不斷layout就可以實現滑動
mRecyclerView.mViewFlinger.postOnAnimation();
}
5.ViewFlinger中,這是實現滑動的重點,省略了很多程式碼邏輯
private class ViewFlinger implements Runnable {
@Override
public void run() {
if (scroller.computeScrollOffset()) {
//呼叫SmoothScroller的onAnimation方法
smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY);
}
}
}
6.SmoothScroller中
private void onAnimation(int dx, int dy) {
//...
if (mTargetView != null) {
// verify target position
if (getChildPosition(mTargetView) == mTargetPosition) {
//要滑動到的位置已經顯示在螢幕上,onTargetFound()方法裡update了差值器,由線性差值器變成了減速的差值器。
onTargetFound(mTargetView, recyclerView.mState, mRecyclingAction);
mRecyclingAction.runIfNecessary(recyclerView);
}
//...
if (mRunning) {
//再下一次滑動
onSeekTargetStep(dx, dy, recyclerView.mState, mRecyclingAction);
//呼叫內部類Action的runIfNecessary方法
mRecyclingAction.runIfNecessary(recyclerView);
}
}
7.Action中
private void runIfNecessary(RecyclerView recyclerView) {
//呼叫了ViewFlinger.smoothScrollBy()方法,並傳入了mDuration,mDuration是在SmoothScroller中upDate()時傳入的,就是由前文講的兩個方法共同決定的
recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration, mInterpolator);
}
8.ViewFlinger中開始滾動
public void smoothScrollBy(int dx, int dy, int duration, Interpolator interpolator) {
if (mInterpolator != interpolator) {
mInterpolator = interpolator;
mScroller = ScrollerCompat.create(getContext(), interpolator);
}
setScrollState(SCROLL_STATE_SETTLING);
mLastFlingX = mLastFlingY = 0;
//呼叫Scroller開始滾動,此處即duration
mScroller.startScroll(0, 0, dx, dy, duration);
postOnAnimation();
}
這塊粗略的按照流程說了一下滾動過程,涉及的類比較多,最終通過Scroller來進行滾動。
結語:
本篇文章實現了RecyclerView的快速滾動,但需要注意一個問題:如果你的Item比較複雜,滾動起來會卡頓。 這個在看原始碼時的一個註釋裡面有提到,後來實踐時確實也發現。不得不說微信朋友圈滑動起來的真的快,它用的是ListView,貌似開啟了FastEnable屬性。
同時也可以仿照知乎,先使用RecyclerView.scrollToPosition(position)直接滑動到某一個位置後再使用smoothScrollToPosition(0)滑動到頂部。這塊在RecyclerView裡的Action類中jumpTo()的註釋裡有提到,如果很遠的話可以先到一個位置後再滑動。
這兩種滑動到頂部的方式都實現了一個小Demo。測試程式碼在GitHub上 FastScrollFragment 。
另外在自己寫的小專案上也用上了 ZhihuDaily,可以檢視這兩個Demo來具體瞭解。
相關推薦
Android RecyclerView 實現快速滑動
前言: 使用RecyclerView時,呼叫smoothScrollToPostion()方法滑動到指定位置,但是條目很多時滑動的很慢,本篇文章就是實現RecyclerView的快速滑動。 先介紹如何實現,然後再介紹原理。 1. 實現程式碼 建立F
Android控制元件RecyclerView實現橫向滑動、瀑布流。
在開發的過程中,我們經常使用ListView控制元件,但是ListView也有它的缺點,就是它不能夠左右滑動資料,執行效率不高; 所以我們可以使用更強大的控制元件RecyclerView,可以說它是一個增強版的ListView,Google推薦使用,那就簡單的
我的Android成長之路(10)----利用recyclerView實現橫向滑動
利用recyclerView實現橫向滑動。 下面是adapter: public class HengAdapter extends RecyclerView.Adapter<HengAdapter.MyViewHolder> implements View.
Android RecyclerView獲得當前滑動的位置
Android本身並沒有提供直接獲得RecyclerView具體位置的api,layoutManager.findFirstCompletelyVisibleItemPosition(); 只是獲得第一個可見的, 因為layoutManager.scrollToPositionWithOffset
android RecyclerView實現檢視更多及收起
三個list: realList 真實list hideList 隱藏時的list openList 展開時的list 做法就是 判斷介面卡條目小於4(可任意)時,將介面卡list設定為真實list 判斷介面卡條目大
Android RecyclerView實現載入多樣式子項
RecyclerView實現載入多種Item佈局 前言 好久沒寫部落格,是時候寫寫部落格了,前面一個月都在找實習、學校實訓事情忙都忙不過來,跑完之後還要去反省,今天哪裡沒做對?哪裡還需要完善?自己的知識哪裡還需要鞏固?等等,牢騷話就不發了,步入正題
Android RecyclerView 實現瀑布流交錯效果,並使最後一行子View高度佔滿RecyclerView
而在實現完瀑布流後,覺得滑動到底部時,最後一行的高度,沒有佔滿外部View,感覺不太好。(真正的瀑布流應該是條目數近乎無窮,可以一直載入更多) 既然是瀑布流,那麼就選用StaggeredGridLayoutManager。 mRecyclerView.s
Android -- RecyclerView實現頂部吸附效果
package com.qianmo.stickyitemdecoration.bean; import java.util.List; /** * Created by Administrator on 2017/3/3 0003. * E-Mail:[email protected]
Android RecyclerView 實現item點選水波紋動畫效果
Recyclerview的item如果如果加上水波紋動畫的點選效果會使列表的ui體驗效果提升很多,今天來給大家介紹一下如何給Recyclerivew的item view新增這樣的動畫效果。 在res目錄的drawable目錄和drawable-v21下分別建立
PopupWindow+RecyclerView實現上下滑動框功能
1.新建一個介面卡繼承自RecyclerView.Adapter package aud.hik.com.audiorecordtool; import android.support.v7.widget.RecyclerView; import android.vie
Android RecyclerView實現側滑刪除
距上次寫部落格有半年多了,回憶起來都覺得不可思議,中間也想憋倆大招,總是被耽誤,這倆月忙完之後,終於空下來了,恰好新專案我和UI倆人商量一下,用MD來實現app。中間有個需求是RecyclerView中側滑顯示刪除按鈕,點選刪除。於是就有了這篇部落格。 一
recyclerView實現左右滑動的效果
這裡是一個通過自定義view和自定義RecyclerView的:layoutManager,再結合ItemTouchHelper實現的一個仿探探的卡片滑動的效果: 對應的介面卡裡面 的 class viewhodler 前面 換成 public 要不調不到 第
recyclerview 實現卡片滑動效果
public void attachToRecyclerView(RecyclerView recyclerView,int margin){ if(recyclerView == null){ return; } mRecycler = recyclerView;
Android TabLayout實現頂部滑動效果(多個頁面)
hvie super title urn page nts bundle image 個數 1.design模式下,將TabLayout 拖入界面中 註意:TabLayout 在container中 2.design模式下,將ViewPager拖入界面中 <
Android從零擼美團(三) - Android多標籤tab滑動切換 - 自定義View快速實現高度定製封裝
這是【從零擼美團】系列文章第三篇 【從零擼美團】是一個高仿美團的開源專案,旨在鞏固 Android 相關知識的同時,幫助到有需要的小夥伴。 GitHub 原始碼地址:github.com/cachecats/L… Android從零擼美團(一) - 統一管理 Gradle 依賴 提取到單獨檔案中 Andr
【Android界面實現】使用PagerTabStrip實現有滑動標簽的Viewpager
n) range over 遊戲娛樂 and ring linear manager ray 在ViewPager這樣的能夠滑動的控件上,總是有非常多的文章能夠做。上次的文章。我們實現了一個自己定義的ViewPager的指示器。這篇文章,我們主要是想利用Andr
Android使用GestureDetector實現手勢滑動效果
void tco event else if rate method sta pro 手勢滑動 直接看實例: package com.example.gesturedetector; import android.os.Bundle; import
Android中關於View滑動的實現你應該知道的
nan ida gif 當前位置 距離 保存 改變 post 控件 滑動作為Android中最基礎的特效之一,使用場景非常廣泛。實現的方式也有多種,理解各種滑動的實現方式。清楚在開發中根據自己的實際需求,選擇合理的實現方案。這篇文章從:scrollTo()/scrollBy
Android基於RecyclerView實現高亮搜索列表
新生代 gil char 能力 hub != AD listview 主動 這篇應該是RecycleView的第四篇了,RecycleView真是新生代的寵兒能做這麽
Android用RecyclerView實現的二維Excel效果組件
eight main AS UC alt 包括 data github AD excelPanel 二維RecyclerView。不僅可以加載歷史數據,而且可以加載未來的數據。 包括在您的項目中 excelPanel 二維RecyclerView。不僅可以加載