在自定義 View 的過程中,如果設(shè)計(jì)到控件的觸摸事件處理颠锉,我們就需要重寫 onTouchEvent()
方法。在這個(gè)方法中最重要的一個(gè)類就是 MotionEvent
類琼掠。下面會(huì)詳細(xì)介紹一下這個(gè)類的各種說明。
獲取位置坐標(biāo)的幾個(gè)方法
在自定義 View 中瓷蛙,有 View.getLeft()
恶复、View.getRight()
速挑、View.getTop()
、View.getBottom()
等方法姥宝,它們的值是本身相對(duì)于父控件的距離,和屏幕沒有關(guān)系腊满。
我們都知道,每個(gè)觸摸事件都代表用戶在屏幕上的一個(gè)動(dòng)作碳蛋,而每個(gè)動(dòng)作必定有其發(fā)生的位置。在 MotionEvent 中就有一系列與標(biāo)觸摸事件發(fā)生位置相關(guān)的函數(shù):
-
getX()
/getY()
:表示觸摸點(diǎn)相對(duì)于控件本身最左邊和最上邊的距離——相對(duì)坐標(biāo)肃弟; -
getRawX()
/getRawY()
:表示觸摸點(diǎn)相對(duì)于屏幕的坐標(biāo)——絕對(duì)坐標(biāo)玷室。
事件類型
MotionEvent 對(duì)象是與用戶觸摸相關(guān)的時(shí)間序列零蓉,該序列從用戶首次觸摸屏幕開始穷缤,經(jīng)歷手指在屏幕表面的任何移動(dòng),直到手指離開屏幕時(shí)結(jié)束津肛。手指的初次觸摸(ACTION_DOWN操作),滑動(dòng)(ACTION_MOVE操作)和抬起(ACTION_UP)都會(huì)創(chuàng)建 MotionEvent 對(duì)象身坐,每次觸摸時(shí)候這三個(gè)操作是肯定發(fā)生的。
MotionEvent.ACTION_DOWN
:當(dāng)屏幕檢測(cè)到第一個(gè)觸點(diǎn)按下之后就會(huì)觸發(fā)到這個(gè)事件;
MotionEvent.ACTION_MOVE
:當(dāng)觸點(diǎn)在屏幕上移動(dòng)時(shí)觸發(fā)部蛇,觸點(diǎn)在屏幕上停留也是會(huì)觸發(fā)的,主要是由于它的靈敏度很高搪花,而我們的手指又不可能完全靜止(即使我們感覺不到移動(dòng),但其實(shí)我們的手指也在不停地抖動(dòng)) ;
MotionEvent.ACTION_POINTER_DOWN
:當(dāng)屏幕上已經(jīng)有觸點(diǎn)處于按下的狀態(tài)的時(shí)候撮竿,再有新的觸點(diǎn)被按下時(shí)觸發(fā);
MotionEvent.ACTION_POINTER_UP
:當(dāng)屏幕上有多個(gè)點(diǎn)被按住,松開其中一個(gè)點(diǎn)時(shí)觸發(fā)(即非最后一個(gè)點(diǎn)被放開時(shí))觸發(fā);
MotionEvent.ACTION_UP
:當(dāng)觸點(diǎn)松開時(shí)被觸發(fā);
MotionEvent.ACTION_CANCEL
:不是由用戶直接觸發(fā)幢踏,由系統(tǒng)在需要的時(shí)候觸發(fā),例如當(dāng)父 view 通過使函數(shù) onInterceptTouchEvent() 返回 true,從子 view 拿回處理事件的控制權(quán)時(shí)房蝉,就會(huì)給子 view 發(fā)一個(gè) ACTION_CANCEL 事件,子 view 就再也不會(huì)收到后續(xù)事件了搭幻。
其它相關(guān)方法
getAction ()
:返回動(dòng)作類型 咧擂;
getActionMasked()
:多點(diǎn)觸控獲取經(jīng)過掩碼后的動(dòng)作類型松申;
getActionIndex()
:多點(diǎn)觸控獲取經(jīng)過掩碼和平移后的索引;
getSize()
:指壓范圍俯逾;
getPressure()
: 壓力值,0-1之間桌肴,看情況,很可能始終返回1坠七,具體的級(jí)別由驅(qū)動(dòng)和物理硬件決定的 旗笔;
getEdgeFlags()
:當(dāng)事件類型是 ActionDown 時(shí)可以通過此方法獲得邊緣標(biāo)記(EDGE_LEFT,EDGE_TOP,EDGE_RIGHT,EDGE_BOTTOM)
离例,但是看設(shè)備情況,很可能始終返回 0;
getDownTime()
:按下開始時(shí)間悉稠;
getEventTime()
: 事件結(jié)束時(shí)間;
getPointerCount()
:獲取觸控點(diǎn)的數(shù)量的猛,比如 2 則可能是兩個(gè)手指同時(shí)按壓屏幕;
getPointerId(nID)
:對(duì)于每個(gè)觸控的點(diǎn)的細(xì)節(jié)卦尊,我們可以通過一個(gè)循環(huán)執(zhí)行 getPointerId 方法獲取索引;
Pointer
為了可以表示多個(gè)觸摸點(diǎn)的動(dòng)作岂却,MotionEvent 中引入了 Pointer 的概念,一個(gè) Pointer 就代表一個(gè)觸摸點(diǎn)躏哩,每個(gè) pointer 都有自己的事件類型,也有自己的橫軸坐標(biāo)值扫尺。
一個(gè) MotionEvent 對(duì)象中可能會(huì)存儲(chǔ)多個(gè) pointer 的相關(guān)信息,每個(gè) pointer 都會(huì)有一個(gè)自己的 id 和 index 正驻。pointer 的 id 在整個(gè)事件流中是不會(huì)發(fā)生變化的,但是index會(huì)發(fā)生變化姑曙。
MotionEvent 類中的很多方法都是可以傳入一個(gè) int 值作為參數(shù)的襟交,其實(shí)傳入的就是 pointer 的 index 值伤靠。比如 getX(pointerIndex) 和 getY(pointerIndex) ,此時(shí)醋界,它們返回的就是 index 所代表的觸摸點(diǎn)相關(guān)事件坐標(biāo)值零聚。
由于 pointer 的 index 值在不同的 MotionEvent 對(duì)象中會(huì)發(fā)生變化攒磨,但是 id 值卻不會(huì)變化蜗字。所以,當(dāng)我們要記錄一個(gè)觸摸點(diǎn)的事件流時(shí)粗梭,就只需要保存其 id ,然后使用 findPointerIndex(int) 來獲得其 index 值断医,然后再獲得其他信息奏纪。
getAction 和 getActionMasked
一個(gè) MotionEvent 對(duì)象中可以包含多個(gè)觸摸點(diǎn)的事件。當(dāng) MotionEvent 對(duì)象只包含一個(gè)觸摸點(diǎn)的事件時(shí)序调,上邊兩個(gè)函數(shù)的結(jié)果是相同的发绢,但是當(dāng)包含多個(gè)觸摸點(diǎn)時(shí),二者的結(jié)果就不同啦默垄。
getAction 獲得的 int 值是由 pointer 的 index 值和事件類型值組合而成的口锭,而 getActionWithMasked 則只返回事件的類型值介杆。
getAction() return 0x0105.
getActionMasked() will return 0x0005
其中 0x0100 就是 pointer 的 index 值。
觸摸事件onTouch/onTouchEvent
設(shè)置觸摸事件有兩種方式荆隘,一種是委托式赴背,一種是回調(diào)式凰荚。
第一種就是將事件的處理委托給監(jiān)聽器處理,你可以定義一個(gè) View.OnTouchListener 接口的子類作為監(jiān)聽器缆毁,實(shí)現(xiàn)它的 onTouch() 方法脊框,onTouch 方法接收一個(gè) MotionEvent 參數(shù)和一個(gè) View 參數(shù)。
第二種是重寫 View 類(在 Android 中任何一個(gè)控件和 Activity 都是間接或者直接繼承于 View)自己本身的 onTouchEvent 方法浇雹,也就是控件自己處理事件昭灵,onTouchEvent 方法僅接收 MotionEvent 參數(shù),這是因?yàn)楸O(jiān)聽器可以監(jiān)聽多個(gè) View 控件的事件硫痰。
或者也可以這樣寫窜护,自定義 View 實(shí)現(xiàn) OnTouchListener 接口柱徙,控件自己處理事件奇昙。
還有更多手勢(shì)操作(雙擊储耐、長(zhǎng)按、滑動(dòng)长赞、滾動(dòng))闽撤、多點(diǎn)觸控等概念哟旗。
參考文章:
Android MotionEvent詳解
Android的MotionEvent和事件處理
本文章只是作為自己學(xué)習(xí)和總結(jié)所用,如有使用不當(dāng)之處可隨時(shí)@我饱亮,謝謝