Android MotionEvent事件響應機制


在android中,事件主要包括點擊、長按、拖曳、滑動等操作,這些構成了Android的事件響應,總體來說,所有的事件都由如下三個部分作為基礎構成:

按下(action_down),移動(action_move),抬起(action_up)。各種響應歸根結底都是基於View以及ViewGroup的,這兩者中響應的方法分別有:

View.java中:

 

publi boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event)

 

ViewGroup.java中

public boolean dispatchTouchEvent(MotionEvent event)
public boolean onTouchEvent(MotionEvent event) 
public boolean onInterceptTouchEvent(MotionEvent event)

在組件嵌套的情況下,對於事件的響應處理會從最頂層的組件不斷向子組件傳遞,一直到最后的View組件。

可以看到ViewGroup中比View中多出了一個onInterceptTouchEvent方法,這是因為ViewGroup組件可以存在子組件,因此需要通過Intercept判斷是否

將該事件傳遞到子組件中。

函數的具體功能如下:

onTouchEvent是真正用來進行業務邏輯處理的地方,返回true表示已經將該事件消費,返回false表明事件繼續傳遞。

onInterceptTouchEvent是用來進行判斷是否需要對事件進行攔截從而阻止其繼續往子組件傳遞的,返回false表示無需攔截,則遞歸的調用子組件的dispatchTouchEvent

方法;返回true表示需要攔截,則直接調用本組件的onTouchEvent方法進行處理。

以上兩個的功能相對好理解一些,最主要的是第三個,之前在網上看了很多,但是都沒有講的特別清楚的。大都說是用於事件分發的,返回true表示不繼續分發,返回false表

示繼續分發。但是一直沒講明白這個跟采用onInterceptTouchEvent的區別在哪里。。

直接點說,Android對於touch事件的處理是通過遞歸來進行的,而這種遞歸就體現在dispatchTouchEvent上。以上所寫的兩個函數就是在dispatchTouchEvent中被調用並

且執行從而實現其分發的業務邏輯的。

在dispatchTouchEvent中有可能會調用三個方法:

1、本組件的onInterceptTouchEvent

2、子組件的dispatchTouchEvent

3、本組件的onTouchEvent

ViewGroup中dispatchTouchEvent()具體的執行邏輯:

1、首先執行本組件的onInterceptTouchEvent。如果返回false,表明無需攔截,則調用第二個方法,即子組件的dispatchTouchEvent方法;如果返回true,無需向子組件

傳遞,則直接調用本組件的onTouchEvent方法

2、第一步中如果需要向子組件傳遞事件。如果遞歸調用子組件的dispatchTouchEvent返回false,則調用本組件的onTouchEvent方法;如果返回true,則無需調用本組件的

onTouchEvent方法

3、根據前兩步的執行結果,將該dispatchTouchEvent的返回值返回給父組件的dispatchTouchEvent方法。

 

view中的dispatchTouchEvent會直接調用其自身的onTouchEvent。

 

一般沒有必要重寫dispatchTouchEvent方法,如果一定要重寫,請注意調用super.dispatchTouchEvent()方法,否則遞歸調用到此處即停止。

在不考慮dispatchTouchEvent的情況下,簡單的執行流程是這樣的:

最頂層的組件首先響應事件,然后不斷向子組件進行傳遞,調用子組件的onInterceptTouchEvent方法,一直到某個組件A的onInterceptTouchEvent

方法返回true或者到達了view組件,然后調用該組件的onTouchEvent方法,之后不斷向父組件進行返回,調用父組件的onTouchEvent直到某個父組件

的onTouchEvent方法返回true。

其實就是個首先從父組件不斷向下調用onInterceptTouchEvent,然后從子組件不斷向上調用onTouchEvent的過程。

還需要注意的:

1、假如這個過程中某個組件截獲並處理了ACTION_DOWN事件,則之后相應的ACTION_MOVE、ACTION_UP等其他事件將不再會被傳遞到他的子孫組

件,而是傳遞到該組件后就執行返回的流程。

2、如果某個組件的onInterceptTouchEvent對ACTION_DOWN返回true,則之后的ACTION_MOVE,ACTION_DOWN等將不會再執行本onInterceptTouchEvent,

而是直接傳遞給本組件的onTouchEvent,但是依然會經過其父組件的onInterceptTouchEvent。

 

 

MotionEvent事件對象

一般我們是在View的onTouchEvent方法中處理MotionEvent對象的.

public boolean onTouchEvent(MotionEvent event)

在這里我們需要從一個MotionEvent對象中獲得哪些信息呢?

(1)首先應該是事件的類型吧?

可以通過getAction(),在android2.2之后加入多點觸控支持之后使用getActionMasked()方法.

這兩個方法的區別見后文.

主要的事件類型有:

ACTION_DOWN: 表示用戶開始觸摸.

ACTION_MOVE: 表示用戶在移動(手指或者其他)

ACTION_UP:表示用戶抬起了手指

ACTION_CANCEL:表示手勢被取消了,一些關於這個事件類型的討論見:http://stackoverflow.com/questions/11960861/what-causes-a-motionevent-action-cancel-in-android

還有一個不常見的:

ACTION_OUTSIDE: 表示用戶觸碰超出了正常的UI邊界.

但是對於多點觸控的支持,Android加入了以下一些事件類型.來處理,如另外有手指按下了,

有的手指抬起來了.等等:

ACTION_POINTER_DOWN:有一個非主要的手指按下了.

ACTION_POINTER_UP:一個非主要的手指抬起來了

(2)事件發生的位置,x,y軸

getX() 獲得事件發生時,觸摸的中間區域在屏幕的X軸.

getY() 獲得事件發生時,觸摸的中間區域在屏幕的X軸.

在多點觸控中還可以通過:

getX(int pointerIndex) ,來獲得對應手指事件的發生位置. 獲得Y軸用getY(int pointerIndex)

(3)其他屬性

getEdgeFlags():當事件類型是ActionDown時可以通過此方法獲得,手指觸控開始的邊界. 如果是的話,有如下幾種值:EDGE_LEFT,EDGE_TOP,EDGE_RIGHT,EDGE_BOTTOM

 

轉載:

http://www.2cto.com/kf/201406/308037.html

https://my.oschina.net/banxi/blog/56421


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM