Scroller類是用于處理滾動效果的一個類,我們平時使用的ViewPager,可以觸摸左右滑動頁面,其內(nèi)部就是使用了Scroller。由于Scroller類是配合View或者ViewGroup的子類來使用的,所以,在了解Scroller類之前,我們先了解一下View的scrollTo方法和ScrollBy方法,下面我們來看看這兩個方法的源碼:

從源碼中可以看出,scrollBy方法其實最終也是調(diào)用scrollTo方法,對于View如果調(diào)用這兩個方法,其實就是移動View中的內(nèi)容,注意是移動View中的內(nèi)容,而不是View自身的位置。如果是ViewGroup調(diào)用這兩個方法,則是移動ViewGroup中的子View的位置。
scrollTo(int x,int y)方法是,將內(nèi)容移動到(x,y)這個坐標(biāo)點(diǎn)處,scrollBy方法將View中的內(nèi)容相當(dāng)于當(dāng)前位置,在x方向移動x距離,在y距離移動y段距離。
講解完View的scrollTo方法和scrollBy方法后,我們再來看看Scroller類,首先看看Scroller類的構(gòu)造方法:

可以看到無論使用哪一個構(gòu)造方法都會調(diào)用第三個構(gòu)造方法,如果沒有指定插值器,系統(tǒng)會為我們創(chuàng)建一個ViscousFluidInterpolator類型的interpolator,flywheel參數(shù)也是根據(jù)版本號來決定的。
一般我們在項目中,使用Scroller的startScroll方法,配合View的invalidate方法,并重寫View的computeScroll方法:


最后效果如圖:可以通過這個鏈接查看。
https://s31.aconvert.com/convert/p3r68-cdx67/rd7mb-3aql1.gif
我們先從smoothScrollTo開始分析,它會調(diào)用scroller.startScroll方法

startScroll方法其實并未做任何的滾動的操作,只是將傳入的參數(shù)進(jìn)行了賦值保存,所以我們在自定義的com.example.myapplication.ScrollView中只是調(diào)用startScroll方法時,并不能起到滾動的效果,還需要使用View的invalidate方法,這時候View的draw方法再次被調(diào)用,同時在draw方法中又會調(diào)用computeScroll方法

這樣,我們重寫的computeScroll方法就會執(zhí)行。

接著調(diào)用scrollTo方法進(jìn)行滾動,然后繼續(xù)invalidate繼續(xù)重繪。繼續(xù)調(diào)用computeScroll,繼續(xù)滾動,接著重繪。通過一連串的這個遞歸調(diào)用,每次滾動一點(diǎn)點(diǎn)距離,整個過程銜接起來就完成了平滑的滾動的效果。那么什么時候退出這個循環(huán)呢?
當(dāng)mScroller的computeScrollOffset方法返回值為false。

可以看到,當(dāng)返回值為true時候,那么它就會一直這樣不停的遞歸,最終完成移動到指定位置的滾動效果,在mFinished時,也就是還未滾動到指定位置時,會先計算一個timePassed,如果這個時間小于指定的滾動時間

而且我們沒設(shè)置mMode這個屬性的話,默認(rèn)是SCROLL_MODE,當(dāng)我們調(diào)用startScroll方法默認(rèn)設(shè)置的。

所以當(dāng)未達(dá)到滾動時間會執(zhí)行SCROLL_MODE這個case,在這個case中,會根據(jù)timePassed,計算出最新的mCurrentX,mCurrentY,這樣我們可以在computeScroll方法中,通過mScroller.getCurrentX();獲取到的是最新的mCurrentX。這樣再調(diào)用scrollTo方法,才會將View的內(nèi)容滾動到最新的位置。
總結(jié):Scroller原理就是:調(diào)用startScroll方法,先告訴系統(tǒng)要移動的起始點(diǎn)和要移動的距離,還有完成的移動的時間,并且配合View的computerScroll方法,通過調(diào)用View的invalidate方法進(jìn)行重繪,這樣computeScroll方法就會執(zhí)行,根據(jù)流失的時間和插值器來計算最新需要移動的位置,然后再通過scrollTo來移動到這個最新的位置,最后通過遞歸來完成整個過程以實現(xiàn)滾動的效果。