系統(tǒng)提供獲取坐標(biāo)值的方法
View提供的獲取坐標(biāo)值方法:
getTop():View本身頂部到其父布局頂部的距離
getLeft():View本身左邊到其父布局左邊的距離
getRight():View本身右邊到其父布局左邊的距離
?getBottom():View本身底部到其父布局頂部的距離?MotionEvent提供的獲取坐標(biāo)值方法:
getX():點(diǎn)擊事件距離View本身左邊的距離
getY():點(diǎn)擊事件距離View本身頂部的距離
getRawX():點(diǎn)擊事件距離屏幕左邊的距離
getRawY():點(diǎn)擊事件距離屏幕頂部的距離
實(shí)現(xiàn)滑動(dòng)的七種方法
1贪惹、layout方法
重寫onTouchEvent()方法,通過MotionEvent的getX()、getY()獲取當(dāng)前觸摸點(diǎn)的坐標(biāo)值甘穿,在MotionEvent.ACTION_MOVE判斷里面計(jì)算偏移量并調(diào)用layout()方法重新調(diào)整View的位置撑螺。注意當(dāng)使用getRawX()、getRawY()方法獲取當(dāng)前觸摸點(diǎn)的坐標(biāo)值時(shí)监憎,需要重新設(shè)置初始坐標(biāo)庆揩。
2痘系、offsetLeftAndRight()和offsetTopAndBottom()
這個(gè)方法相當(dāng)于系統(tǒng)提供的一個(gè)對(duì)左右、上下移動(dòng)的API封裝饿自,當(dāng)計(jì)算出偏移量后汰翠,只需要調(diào)用該方法并傳入偏移量參數(shù)即可,效果與layout()一樣昭雌。
3复唤、LayoutParams
使用 getLayoutParams() 方法獲取 LayoutParams 時(shí),需要根據(jù) View 所在父布局的類型
來設(shè)置不同的類型進(jìn)行強(qiáng)制轉(zhuǎn)換烛卧,如果沒有父布局是無法獲取 LayoutParams 參數(shù)的佛纫。或者
可以直接使用 ViewGroup.MarginLayoutParams 直接改變 View 的 Margin 屬性总放。
4呈宇、scrollTo()、scrollBy()
scrollTo(x, y)表示移動(dòng)到一個(gè)具體的坐標(biāo)點(diǎn)(x, y)局雄;scrollBy(dx, dy)表示移動(dòng)的增量為dx攒盈、dy;
特別注意:
(1)scrollTo()哎榴、scrollBy()方法移動(dòng)的是View的content內(nèi)容型豁,例如TextView的content就是文本,ImageView的content就是Drawable對(duì)象尚蝌;如果在ViewGroup中使用scrollTo()迎变、scrollBy()方法,那么移動(dòng)的就是所有的子View飘言。
(2)如果從左往右滑動(dòng)衣形,那么mScrollX為負(fù)值,反之為正值姿鸿。
5、Scroller類
通過Scroller類可以實(shí)現(xiàn)平滑移動(dòng)的效果苛预,而不再是瞬間完成的移動(dòng)句狼。
具體使用方法如下:
(1)通過構(gòu)造方法初始化一個(gè)Scroller對(duì)象;
(2)重寫computeScroll()方法热某,實(shí)現(xiàn)模擬滑動(dòng)腻菇;
(3)調(diào)用startScroll()方法開啟滑動(dòng)胳螟;
注意點(diǎn):
(1)View類的computeScroll()方法是使用Scroller類的核心,系統(tǒng)在繪制View的時(shí)候會(huì)在draw()方法中調(diào)用筹吐;computeScroll()方法在View中是一個(gè)空實(shí)現(xiàn)糖耸,需要我們自己實(shí)現(xiàn)它,一般在該方法里調(diào)用scrollTo()實(shí)現(xiàn)模擬滑動(dòng)丘薛。但是computeScroll()方法不會(huì)自動(dòng)調(diào)用嘉竟,只能通過invalidate() -> draw() ->?computeScroll()來間接調(diào)用,所以一般需要在該方法最后添加invalidate()方法進(jìn)行重繪洋侨。
(2)Scroller類的computeScrollOffset()方法用于判斷是否完成整個(gè)滑動(dòng)周拐,如果完成了滑動(dòng)則返回false,否則返回true凰兑。
(3)Scroller類提供getCurrX()和getCurrY()方法來獲取當(dāng)前的滑動(dòng)坐標(biāo)妥粟。
(4)Scroller類的startScroll()方法有兩個(gè)重載方法,可以設(shè)置duration參數(shù)來確定滑動(dòng)時(shí)間(默認(rèn)是250ms)吏够;前兩個(gè)參數(shù)表示起始坐標(biāo)勾给,后兩個(gè)參數(shù)表示偏移量,在獲取坐標(biāo)時(shí)通彻可以使用getScrollX()和getScrollY()方法來獲取父視圖中View所滑動(dòng)到的點(diǎn)的坐標(biāo)播急。
Scroller的工作原理:
Scroller本身并不能實(shí)現(xiàn)滑動(dòng)效果,必須結(jié)合View的computeScroll()方法才能完成彈性滑動(dòng)的效果售睹,它不斷讓View重繪桩警,而每一次重繪距離滑動(dòng)起始時(shí)間會(huì)有一個(gè)時(shí)間間隔(duration),通過這個(gè)時(shí)間間隔Scroller 就可以得出View當(dāng)前的滑動(dòng)位置昌妹,知道了滑動(dòng)位置就可以通過scrollTo() 方法來實(shí)現(xiàn)滑動(dòng)捶枢。就這樣,View的每一次重繪都會(huì)導(dǎo)致View進(jìn)行小幅度的滑動(dòng)飞崖,而多次小幅度滑動(dòng)在視覺上就形成了彈性滑動(dòng)烂叔。
Scroller的源碼解析:
Scroller類的startScroll()方法并沒有調(diào)用類似開啟滑動(dòng)的方法,而是保存了傳進(jìn)來的各種參數(shù):startX和startY表示滑動(dòng)開始的起點(diǎn)固歪,dx和dy表示滑動(dòng)的距離蒜鸡,duration表示滑動(dòng)持續(xù)的時(shí)間。所以 startScroll()方法只是用來做前期準(zhǔn)備的牢裳,并不能使View進(jìn)行滑動(dòng)逢防。關(guān)鍵在于我們在 startScroll()方法后面調(diào)用了invalidate()方法,這個(gè)方法會(huì)導(dǎo)致View重繪蒲讯,而View的重繪會(huì)調(diào)用draw()方法忘朝,draw()方法又會(huì)調(diào)用View的computeScroll()方法。
我們在computeScroll()方法中通過Scroller來獲取當(dāng)前的ScrollX和ScrollY伶椿,然后調(diào)用scrollTo()方法進(jìn)行真正的滑動(dòng)辜伟,接著調(diào)用invalidate()方法讓View進(jìn)行重繪,而重繪又會(huì)調(diào)用 computeScroll()方法實(shí)現(xiàn)View的滑動(dòng)脊另,這樣通過不斷移動(dòng)一個(gè)小的距離并連貫起來就實(shí)現(xiàn)了平移滑動(dòng)的效果导狡。
但是如何獲取當(dāng)前的ScrollX和ScrollY呢?在 computeScrollOffset()方法中偎痛,首先會(huì)計(jì)算動(dòng)畫持續(xù)的時(shí)間timePassed旱捧,如果動(dòng)畫持續(xù)的時(shí)間小于我們設(shè)置的滑動(dòng)持續(xù)時(shí)間mDuration,就會(huì)進(jìn)入switch語句踩麦,由于startScroll()方法設(shè)置的mMode為SCROLL_MODE枚赡,所以只會(huì)執(zhí)行分支語句SCROLL_MODE,然后根據(jù)插值器Interpolator來計(jì)算出在該段時(shí)間內(nèi)的移動(dòng)距離谓谦,并賦值給mCurrX和mCurrY贫橙。所以可以直接通過Scroller的getCurrX()和getCurrY()方法獲取當(dāng)前的ScrollX和ScrollY。
6反粥、屬性動(dòng)畫
7卢肃、ViewDragHelper
通過ViewDragHelper基本可以實(shí)現(xiàn)各種不同的滑動(dòng)、拖放需求才顿,因此這個(gè)方法也是各種滑動(dòng)解決方案中的終極絕招莫湘,但是使用起來比較復(fù)雜。Google在其support庫中為我們提供了DrawerLayout和SlidingPaneLayout兩個(gè)布局來幫助開發(fā)者實(shí)現(xiàn)側(cè)邊欄滑動(dòng)的效果郑气,這兩個(gè)布局底層就是使用ViewDragHelper來實(shí)現(xiàn)的幅垮。