【Android View事件(四)】View滑動與實現(xiàn)滑動的幾種方法

【大圣代的技術(shù)專欄 http://blog.csdn.net/qq_23191031 轉(zhuǎn)載煩請注明出處栅哀,尊重他人勞動成功就是對您自己的尊重】

相關(guān)文章
詳解Android控件體系與常用坐標(biāo)系
Android常用觸控類分析:MotionEvent 甚亭、 ViewConfiguration、VelocityTracker
Android View事件(二)詳解事件分發(fā)機制

一, 前言

在前面的幾篇文章,我向大家介紹的都是單一View事件,而在這篇文章中,我將向大家介紹連續(xù)的事件 —— 滑動累舷。
在安卓設(shè)備上滑動幾乎是應(yīng)用的標(biāo)配,由于安卓手機屏幕較小夹孔,為了給用戶呈現(xiàn)更多的內(nèi)容被盈,就需要使用滑動來隱藏和顯示一些內(nèi)容析孽。學(xué)習(xí)View的滑動對于自定義控件的掌握、日持辉酰滑動沖突的處理都有很多裨益袜瞬。為了很好的理解滑動事件,掌握Android坐標(biāo)系與觸控事件就變得格外重要身堡,在此強烈建議先閱讀上面的提到的幾篇相關(guān)文章打好基礎(chǔ)邓尤。

二, View滑動產(chǎn)生的原理

從原理上講View滑動的本質(zhì)就是隨著手指的運動不斷地改變坐標(biāo)贴谎。當(dāng)觸摸事件傳到View時汞扎,系統(tǒng)記下觸摸點的坐標(biāo),手指移動時系統(tǒng)記下移動后的觸摸的坐標(biāo)并算出偏移量擅这,并通過偏移量來修改View的坐標(biāo)澈魄,不斷的重復(fù)這樣的過程,從而實現(xiàn)滑動過程蕾哟。

三一忱,實現(xiàn)滑動的7種方法

在學(xué)習(xí)Android坐標(biāo)系和觸控事件之后我們就可以看看系統(tǒng)為開發(fā)者提供了那些方法來實現(xiàn)滑動效果吧莲蜘!

3.0 代碼實例介紹

為了讓大家更好的理解過程谭确,設(shè)計如下代碼實例

代碼結(jié)構(gòu)
主要布局
CustomView具體結(jié)構(gòu)

MainActivity中沒有任何改動,而CustomView只是繼承了View票渠,并重寫了 onToucnEvent()方法逐哈。

可以看到代碼很簡單,這篇文章中我就不提供項目地址了问顷。

3.1 layout 方法

在View繪制的時候昂秃,系統(tǒng)都會調(diào)用layout(int l, int t, int r, int b)方法來確定View的具體位置。系統(tǒng)既然是這樣來設(shè)置View的位置的杜窄,那么我們也可以通過調(diào)用layout(int l, int t, int r, int b)`方法修改left肠骆,top,right塞耕,bottom這四個屬性來控制View的位置蚀腿。

    // 視圖坐標(biāo)方式
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 記錄觸摸點坐標(biāo)
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                // 計算偏移量
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                // 在當(dāng)前l(fā)eft、top扫外、right莉钙、bottom的基礎(chǔ)上加上偏移量
                layout(getLeft() + offsetX,
                        getTop() + offsetY,
                        getRight() + offsetX,
                        getBottom() + offsetY);
                break;
        }
        return true;
    }

當(dāng)然使用 getX()getY()方法和使用getRawX()筛谚、geRawtY()的效果是一樣的磁玉,只不過前者使用的是相對位置,而后者使用的是絕對位置驾讲。
但是要注意蚊伞,在使用絕對坐標(biāo)系的時候席赂,每次執(zhí)行完 ACTION_MOVE的邏輯后,一定要重新設(shè)置初始坐標(biāo)时迫,這樣才能獲得準確的偏移量氧枣。

     case MotionEvent.ACTION_MOVE:
                // 計算偏移量
              …………
  
              //重新設(shè)置初始坐標(biāo)
              x = (int)(event.getRawX());
              y = (int)(event.getRawY());
                break;

3.2 offsetLeftAndRight() 與 offsetTopAndroidBottom()

    // 視圖坐標(biāo)方式
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 記錄觸摸點坐標(biāo)
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                // 計算偏移量
                int offsetX = x - lastX;
                int offsetY = y - lastY
                //同時對于left 和 right進行偏移
                offsetLeftAndRight(offsetX);
                //同時對于top 和 bottom進行偏移
                offsetTopAndBottom(offsetY);
                break;
        }
        return true;
    }

3.3 LayoutParams

LayoutParams類是子View向父View傳遞位置意圖的橋梁,告訴父View他想要變成的樣子别垮。所以我們可以通過LayoutParams中的參數(shù)來改變View的位置便监。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int startX = (int) event.getX();
        int startY = (int) event.getY();
        int lastX = 0;
        int lastY = 0;

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = startX;
                lastY = startY;
                Log.v(TAG, "startX   " + startX + "    startY      " + startY);
                break;
            case MotionEvent.ACTION_MOVE:
                Log.v(TAG, "offsetX ---  " + startX + "    offsetY ---     " + startY);
                int offsetX = startX - lastX;
                int offsetY = startY - lastY;
                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
                layoutParams.leftMargin = getLeft() + offsetX;
                layoutParams.topMargin = getTop() + offsetY;
                setLayoutParams(layoutParams);
                break;
        }
        //注明消費此事件,不然無效果
        return true;
    }

注意:

在獲得 LayoutParams對象的時候碳想,需要將其轉(zhuǎn)換成直接父View(這個View的上一層布局)的類型烧董,不然會報錯。
例如胧奔,將

    LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();

改為錯誤的:

    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();

報錯如下:

3.4 scrollTo與ScrollBy

在View中系統(tǒng)為開發(fā)者提供了兩個關(guān)于移動的方法: scrollTo 與 scroolBy逊移。其實這兩個方法非常好理解,單從字面上的意思就知道

scrollTo(x,y) : 移動到 (x,y) 這個坐標(biāo)點
scrlollBy(dx,dy) : 移動的增量為 dx龙填,dy胳泉。

我們對于原有代碼進行如下更改

但是,當(dāng)我們拖動View的時候卻沒有移動Q乙拧I壬獭!這是為什么呢宿礁?
其實View是移動了地案铺,只不過和我們設(shè)想的結(jié)果不同。scrollTo()梆靖、scrollBy()表示的是 移動當(dāng)前ViewGroup的所有子View控汉,如果在View中使用,那么移動的就是View的內(nèi)容(content)返吻。例如TextView它的content就是文本姑子。這就解釋了為什么我們的代碼看不到效果了。

將原有代碼更改為如下所示:

  ((ViewGroup) getParent()).scrollBy(offsetX, offsetY);

這回的確是動了测僵,但是他卻在亂動街佑。并不是像我們想象中的那樣跟隨著手指的移動而移動。

導(dǎo)致這個的原因是什么呢恨课? 答案請見《Scroll類源碼分析與應(yīng)用》第一節(jié) scrollTo與ScrollBy

3.5 Scroller

請見《Scroll類源碼分析與應(yīng)用》 第二節(jié)Scroller

關(guān)于屬性動畫舆乔、ViewDragHelper

二者也是實現(xiàn)View滑動的良好辦法,但是他們都有一定的復(fù)雜性直接展開不僅顯得突兀剂公、而且篇幅較大不利于學(xué)習(xí)希俩,所以屬性動畫與ViewDragHelper我都會以單獨的篇幅展開,方便同學(xué)們更好的理解與學(xué)習(xí)纲辽,敬請期待

版權(quán)聲明:
禁止一切商業(yè)行為颜武,轉(zhuǎn)載請著名出處 http://blog.csdn.net/qq_23191031璃搜。作者: 大圣代
Copyright (c) 2017 代圣達. All rights reserved.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鳞上,隨后出現(xiàn)的幾起案子这吻,更是在濱河造成了極大的恐慌,老刑警劉巖篙议,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唾糯,死亡現(xiàn)場離奇詭異,居然都是意外死亡鬼贱,警方通過查閱死者的電腦和手機移怯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來这难,“玉大人舟误,你說我怎么就攤上這事∫雠遥” “怎么了嵌溢?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蹋岩。 經(jīng)常有香客問我赖草,道長,這世上最難降的妖魔是什么星澳? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任疚顷,我火速辦了婚禮旱易,結(jié)果婚禮上禁偎,老公的妹妹穿的比我還像新娘。我一直安慰自己阀坏,他們只是感情好如暖,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忌堂,像睡著了一般盒至。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上士修,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天枷遂,我揣著相機與錄音,去河邊找鬼棋嘲。 笑死酒唉,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沸移。 我是一名探鬼主播痪伦,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侄榴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了网沾?” 一聲冷哼從身側(cè)響起癞蚕,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辉哥,沒想到半個月后桦山,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡醋旦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年度苔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浑度。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡寇窑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出箩张,到底是詐尸還是另有隱情甩骏,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布先慷,位于F島的核電站饮笛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏论熙。R本人自食惡果不足惜福青,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脓诡。 院中可真熱鬧无午,春花似錦、人聲如沸祝谚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽交惯。三九已至次泽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間席爽,已是汗流浹背意荤。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留只锻,地道東北人玖像。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像炬藤,于是被迫代替她去往敵國和親御铃。 傳聞我的和親對象是個殘疾皇子碴里,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

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

  • 內(nèi)容是博主照著書敲出來的,博主碼字挺辛苦的上真,轉(zhuǎn)載請注明出處咬腋,后序內(nèi)容陸續(xù)會碼出。 當(dāng)了解了Android坐標(biāo)系和觸...
    Blankj閱讀 6,639評論 3 61
  • 什么是View View 是 Android 中所有控件的基類睡互。 View的位置參數(shù) View 的位置由它的四個頂...
    acc8226閱讀 1,170評論 0 7
  • 開發(fā)中根竿,為了增加更多炫麗的效果,我們經(jīng)常在應(yīng)用中添加滑動效果就珠,今天就來分析一下 View 中滑動效果的實現(xiàn)原理以及...
    任教主來也閱讀 2,971評論 0 14
  • 聲明:本文內(nèi)容根據(jù)《Android開發(fā)藝術(shù)探索》的思路寇壳,基于 API 26 進行總結(jié) 一、Android View...
    Marker_Sky閱讀 1,754評論 0 4
  • 看完西游記妻怎,有這樣一種感覺壳炎,就好像多年的好友,一起相處了很長時間逼侦,一起經(jīng)歷很多事匿辩,到最后終于還是要分離。雖然以后也...
    單海閱讀 227評論 0 2