View 的滑動原理和實現(xiàn)方式

開發(fā)中陨瘩,為了增加更多炫麗的效果,我們經(jīng)常在應(yīng)用中添加滑動效果级乍,今天就來分析一下 View 中滑動效果的實現(xiàn)原理以及幾種常見的實現(xiàn)方式舌劳。

一、滑動原理

1. Android 中的坐標系

View 基礎(chǔ) 中我們提到了 View 中的 X玫荣、Y甚淡、mLeft、mTop... 等屬性捅厂,其中這些屬性的值都是相對坐標系來說的贯卦,Android 中有兩種坐標系,這里一一來簡單說一下

Android 坐標系: 以屏幕左上角為坐標原點撵割,向右為 X 軸正方向辙芍,向下為 Y 軸正方向啡彬,MotionEvent 的 getRawX()、getRawY() 方法獲取的是點擊位置在 Android 坐標系中的坐標

視圖坐標系: 以當前控件左上角為坐標原點故硅,向右為 X 軸正方向庶灿,向下為 Y 軸正方向,MotionEvent 的 getX()吃衅、getY() 方法獲取的是點擊位置在視圖坐標系中的坐標峻呕,View 的 mLeft、mTop 等屬性也是 View 在父控件的視圖坐標系中的坐標

2. 滑動原理

了解了 Android 中的坐標系趣效,再說 View 的滑動原理山上,其實滑動的原理與動畫效果的實現(xiàn)非常相似,都是通過不斷改變 View 的坐標來實現(xiàn)這一效果英支。所以要實現(xiàn)滑動效果就必須要監(jiān)聽用戶的觸摸事件佩憾,并根據(jù)事件傳入的坐標,動態(tài)且不斷的改變 View 的坐標,從而實現(xiàn) View 跟隨用戶觸摸的滑動而滑動

二妄帘、滑動方式

滑動過程中觸摸坐標改變的監(jiān)聽功能我們可以通過重寫 onTouchEvent() 方法實現(xiàn)楞黄,onTouchEvent 中根據(jù)事件類型確定當前的觸摸坐標,如果如果需要實現(xiàn)滑動抡驼,再調(diào)用實現(xiàn)滑動的方法鬼廓。

通過滑動原理我們知道所有修改 View 坐標的方法都可以實現(xiàn)滑動功能,而改標 View 坐標的方式有很多種致盟,這里我們就介紹幾種常見的滑動方式

1. 通過 layout() 方法

View 中通過滑動事件中計算滑動距離碎税,調(diào)用 layout 方法,其原理是改變 View 的 mLeft馏锡、mTop 等坐標雷蹂,將初始位置值及偏移量傳入,即需要滑動到的位置的坐標杯道,由上篇文章介紹的 layout 過程 可知匪煌,View 完成重新布局后,就達到了移動 View 的效果

2. offsetLeftAndRight() 方法和 offsetTopAndBottom()

offsetLeftAndRight(offset) offsetTopAndBottom(offset) 方法的原理是通過修改 View 的 mLeft党巾、mTop 坐標完成滑動萎庭。

在滑動事件中,得到偏移量齿拂,調(diào)用 offsetLeftAndRight 和 offsetLeftAndRight 方法實現(xiàn)滑動

3. 通過修改 LayoutParams 實現(xiàn)滑動

通過改變 View 的 LayoutParams 參數(shù)中的 margin 值驳规,在父 View 的布局過程中會將 View 的坐標加上相應(yīng)的 margin 偏移量,從而改變 View 在父容器中的坐標署海,完成滑動

4.使用動畫

  • 使用 View 動畫达舒,只能改變 View 內(nèi)容的位置,不能改變 View 的真正坐標

  • 使用屬性動畫完成滑動叹侄,在動畫執(zhí)行的過程中巩搏,通過改變 View 的真正坐標實現(xiàn)滑動

這里總結(jié)一下,以上介紹的前三種滑動方式以及使用屬性動畫完成滑動趾代,這些方式都是通過改變 View 在其父容器中的坐標從而實現(xiàn)的滑動贯底,實現(xiàn)的是控件整體發(fā)生了滑動

5. View 的 scrollTo()、scrollBy() 方法實現(xiàn)滑動

scrollTo撒强、scrollBy 實現(xiàn)的是 View 內(nèi)容的滑動,是區(qū)別于上面提到的控件整體滑動的禽捆,其效果是 View 控件并沒有滑動,而是控件上繪制的內(nèi)容在控件范圍內(nèi)發(fā)生了滑動

在發(fā)生滑動事件時飘哨,通過調(diào)用 scrollTo 或者 scrollBy 方法完成 View 內(nèi)容的滑動胚想。

如果想要通過 scrollTo/scrollBy 方法實現(xiàn) View 控件的滑動,就在需要滑動的時候芽隆,調(diào)用 view.getParent().scrollTo 浊服,通過讓其父 View 滑動其父 View 中的內(nèi)容统屈,實現(xiàn)該 View 的滑動效果。

并且還有一點需要注意:如果通過其父 View 調(diào)用 scrollTo/scrollBy 方法改變所以子 View 在父 View 中的位置時牙躺,并沒有修改子 View 真正的坐標位置愁憔,而是修改了坐標的偏移量 translateX、translateY 孽拷、x吨掌、y 的值,其中 x = mLeft + translateX 脓恕,y 同理

scrollTo/scrllBy 方法的區(qū)別

  • scrollTo(int x,int y) 實現(xiàn)的是相對于參數(shù)的絕對滑動膜宋,即滑動結(jié)果為相對于內(nèi)容的原始位置,原始位置就是 mScrollX 和 mScrollY 都是 0 的位置,滑動后 mScrollX = x ; mScrollY = y;

  • scrollBy(int x,int y) 中調(diào)用了 scrollTo() 方法炼幔,不過 scrollBy() 實現(xiàn)的是相對于當前位置的相對滑動秋茫,即相對于當前 mScrollX 和 mScrollY 的值進行的滑動,滑動結(jié)果為 mScrollX = x + mScrollX(滑動前) mScrollY = y + mScrollY(滑動前)

View 的 mScrollX 和 mScrollY 參數(shù)

  • mScrollX 可由 getScrollX() 方法得到江掩,表示的是学辱,View 左邊緣跟 View 內(nèi)容左邊緣在水平方向的距離乘瓤,并且环形,如果 View 左邊緣在內(nèi)容左邊緣左側(cè)時該值為負,View 左邊緣在內(nèi)容左邊緣右側(cè)時該值為正衙傀。

  • mScrollY 可由 getScrollY() 方法得到抬吟,表示的是,View 上邊緣跟 View 內(nèi)容上邊緣在豎直方向的距離统抬,并且火本,如果 View 上邊緣在內(nèi)容上邊緣上側(cè)時該值為負,View 左邊緣在內(nèi)容左邊緣右側(cè)時該值為正聪建。

6. 通過 Scroller 類實現(xiàn)滑動

Scroller 實現(xiàn)滑動的原理是通過調(diào)用 scrollTo 方法實現(xiàn)的钙畔,所以實現(xiàn)的也是內(nèi)容的滑動,有關(guān)內(nèi)容滑動的知識請看上一節(jié)通過 scrollTo 方法實現(xiàn)滑動效果

實現(xiàn)方式:

  1. 初始化 Scroller 金麸,調(diào)用 Scroller 的 startScroll 方法擎析,將 X,Y 方向的初始挥下、需要偏移值揍魂、滑動初始時間以及滑動時間傳入,如果不傳入滑動時間棚瘟,則默認時間為 250 毫秒现斋,接著調(diào)用 invalidate() 方法執(zhí)行重繪

  2. 重寫 View 的 cumputeScroll 方法,在重繪過程中調(diào)用該方法偎蘸。其中通過調(diào)用 Scroller 對象的 computeScrollOffset 方法測量當前時間對應(yīng)的應(yīng)該發(fā)生滑動值庄蹋,并將最新的需要滑動的值保存瞬内,該方法返回是否滑動完成的 boolean 值,true 滑動未完成蔓肯,返回 false 表示滑動已經(jīng)完成遂鹊。computeScrollOffset 方法中通過時間的流逝計算當前需要滑動到的位置。

  3. cumputeScroll 中蔗包,如果滑動未完成秉扑,通過 scroller 的 getScrollX getScrollY ,得到當前需要滑動到的位置调限,調(diào)用 View 的 scrollTo 方法滑動到指定位置舟陆,

  4. 再次調(diào)用 invalidate 方法,實現(xiàn) View 的重繪耻矮。

再總結(jié)一下 Scroller 實現(xiàn)滑動的過程秦躯,invalidate 方法執(zhí)行重繪,重繪過程中會調(diào)用 cumputeScroll 方法裆装,cumouteScroll 方法中又會通過 Scroller 來計算當前需要滑動到的位置并調(diào)用滑動方法實現(xiàn)滑動踱承,接著在調(diào)用 invalidate 方法重繪,從而循環(huán)繪制哨免,直到滑動完成

7. ViewDragHelper 實現(xiàn)滑動

ViewDragHelper 是 Google 提供的一個類茎活,通過 ViewDragHelper 來實現(xiàn)各種不同的滑動,拖放需求

  1. ViewGroup 中初始化琢唾,傳入 ViewGroup 和 回調(diào) CallBack 载荔,Callback 中的方法返回值表示哪個 View 可以被移動
  2. 攔截事件,將 View 的觸摸事件使用 ViewDragHelper 的方法攔截
  3. 重寫 View 的 computeScroll 方法
  4. 在回調(diào)中重寫監(jiān)聽方法采桃,clampViewPositionHorizontal clampViewPositionVertical 實現(xiàn)橫向縱向滑動
  5. 可以通過重寫不同狀態(tài)的回調(diào)實現(xiàn)在不同回調(diào)時的實現(xiàn)懒熙。

好啦,到這里有關(guān) View 滑動的內(nèi)容就介紹的差不多了普办,其中要區(qū)分滑動實現(xiàn)的是 View 控件的滑動工扎,還是 View 內(nèi)容的滑動。并且通過動畫衔蹲、Scroller肢娘、Handler/postDelay 等方式還可以實現(xiàn)彈性滑動的效果,普通滑動都是瞬時完成的踪危,而彈性滑動則是漸進完成的蔬浙,如果不太了解彈性滑動的只需要實現(xiàn)前面提到的幾種滑動方式,一對比就明白啦贞远。

請期待下篇文章觸摸事件的分發(fā)和處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末畴博,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蓝仲,更是在濱河造成了極大的恐慌俱病,老刑警劉巖官疲,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異亮隙,居然都是意外死亡途凫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門溢吻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來维费,“玉大人,你說我怎么就攤上這事促王∠耍” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵蝇狼,是天一觀的道長阅畴。 經(jīng)常有香客問我,道長迅耘,這世上最難降的妖魔是什么贱枣? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮颤专,結(jié)果婚禮上纽哥,老公的妹妹穿的比我還像新娘。我一直安慰自己血公,他們只是感情好昵仅,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布缓熟。 她就那樣靜靜地躺著累魔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪够滑。 梳的紋絲不亂的頭發(fā)上垦写,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音彰触,去河邊找鬼梯投。 笑死,一個胖子當著我的面吹牛况毅,可吹牛的內(nèi)容都是我干的分蓖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼尔许,長吁一口氣:“原來是場噩夢啊……” “哼么鹤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起味廊,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤蒸甜,失蹤者是張志新(化名)和其女友劉穎棠耕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柠新,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了太雨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片验夯。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖憔恳,靈堂內(nèi)的尸體忽然破棺而出咕痛,到底是詐尸還是另有隱情,我是刑警寧澤喇嘱,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布茉贡,位于F島的核電站,受9級特大地震影響者铜,放射性物質(zhì)發(fā)生泄漏腔丧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一作烟、第九天 我趴在偏房一處隱蔽的房頂上張望愉粤。 院中可真熱鬧,春花似錦拿撩、人聲如沸衣厘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽影暴。三九已至,卻和暖如春探赫,著一層夾襖步出監(jiān)牢的瞬間型宙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工伦吠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留妆兑,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓毛仪,卻偏偏與公主長得像搁嗓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子箱靴,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 什么是View View 是 Android 中所有控件的基類腺逛。 View的位置參數(shù) View 的位置由它的四個頂...
    acc8226閱讀 1,170評論 0 7
  • 內(nèi)容是博主照著書敲出來的,博主碼字挺辛苦的刨晴,轉(zhuǎn)載請注明出處屉来,后序內(nèi)容陸續(xù)會碼出路翻。 當了解了Android坐標系和觸...
    Blankj閱讀 6,639評論 3 61
  • 在Android中想要實現(xiàn)實現(xiàn)滑動有很多方法,這篇博客將提供一些實現(xiàn)滑動的思路茄靠,希望可以幫助到有需要的人茂契。 一、A...
    冰鑒IT閱讀 14,445評論 11 77
  • 目前移動設(shè)備流行慨绳,我們要在如此小的屏幕上盡可能給用戶展現(xiàn)更多的內(nèi)容掉冶,就需要在應(yīng)用上通過滑動來顯示和隱藏部分內(nèi)容,V...
    shenhuniurou閱讀 968評論 2 1
  • 1. wait()函數(shù) 頭文件:#include / 函數(shù)的一般形式: 參數(shù)設(shè)置: 返回值:如果執(zhí)行成功則返回子...
    一葉之界閱讀 21,241評論 0 2