1. 程式人生 > >Android RecyclerView 實現快速滑動

Android RecyclerView 實現快速滑動

前言:

使用RecyclerView時,呼叫smoothScrollToPostion()方法滑動到指定位置,但是條目很多時滑動的很慢,本篇文章就是實現RecyclerView的快速滑動。

先介紹如何實現,然後再介紹原理。

1. 實現程式碼

  1. 建立FastScrollLinearLayoutManager,繼承LinearLayoutManager
  2. 複寫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真是新生代的寵兒能做這麽

AndroidRecyclerView實現的二維Excel效果組件

eight main AS UC alt 包括 data github AD excelPanel 二維RecyclerView。不僅可以加載歷史數據,而且可以加載未來的數據。 包括在您的項目中 excelPanel 二維RecyclerView。不僅可以加載