android觸控,先了解MotionEvent(一)

這是我我的的見解,要學好android觸控,瞭解MotionEvent是必要,對所用的MotionEvent經常使用的API要比較深刻的瞭解. java

下面是我我的的學習過程記錄: android

android.view.MotionEvent git

MotionEvent源代碼能夠在ocs看到,固然你也能夠在SDK中下載源代碼,或者其餘地方,如: github

https://github.com/android/platform_frameworks_base/blob/master/core/java/android/view/MotionEvent.java ide


    MotionEvent事件對象

通常咱們是在View的onTouchEvent方法中處理MotionEvent對象的. 學習

    public boolean onTouchEvent(MotionEvent event)  spa

在這裏咱們須要從一個MotionEvent對象中得到哪些信息呢? .net

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

  能夠經過getAction(),在android2.2以後加入多點觸控支持以後使用getActionMasked()方法. 翻譯

  這兩個方法的區別見後文. code

 主要的事件類型有:

 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





 一些討論

(1)首先是MotionEvent 中getAction()getActionMasked()的區別:

 首先看代碼:

/**
     * Bit mask of the parts of the action code that are the action itself.
     */
    public static final int ACTION_MASK             = 0xff;

/**
     * Return the kind of action being performed.
     * Consider using {@link #getActionMasked} and {@link #getActionIndex} to retrieve
     * the separate masked action and pointer index.
     * @return The action, such as {@link #ACTION_DOWN} or
     * the combination of {@link #ACTION_POINTER_DOWN} with a shifted pointer index.
     */
    public final int getAction() {
        return mAction;
    }

  /**
     * Return the masked action being performed, without pointer index information.
     * Use {@link #getActionIndex} to return the index associated with pointer actions.
     * @return The action, such as {@link #ACTION_DOWN} or {@link #ACTION_POINTER_DOWN}.
     */
    public final int getActionMasked() {
        return mAction & ACTION_MASK;
    }

上面的代碼是基於android2.2的,註釋是android4.X中最新的.

他們有什麼區別呢?若是mAction的值是在0x00到0xff之間的話。getAction()返回的值,和

getActionMasked()的返回的值是同樣的。

(Q1)那何時返回的值是同樣的呢?即當mAction值大於0xff時,那何時會大於0xff呢?

  這就是是當有多點觸控時。當有多點觸控時。

 mAction的低8位即0x00到0xff用來表示動做的類型信息。

 例如:MotionEvent#ACTION_DOWN的值是 0,即0x00。

         MotionEvent#ACTION_UP的值是 1,即0x01。

  等等。

 可是,咱們知道Android是支持多點觸控的,那麼怎麼知道這個一個MotionEvent是哪個

觸控點觸發的呢?那麼就還須要MotionEvent帶有觸控點索引信息。

 Android的解決方案時在;mAction的第二個8位中存儲。

例如,若是mAction的值是0x0000,則表示是第一個觸控點的ACTION_DOWN操做。

       若是mAction的值是0x0100呢,則表示是第二個觸控點的ACTION_DOWN操做。

       第三個的ACTION_DOWN呢?相信你能夠推出來是0x0200。

總而言之,mAction時的低8位(也就是0-7位)是動做類型信息。

            mAction的8-15位呢,是觸控點的索引信息。(即表示是哪個觸控點的事件)。

(Q2),爲何不用兩個字段來表示。

如   int mAction,int mPointer,

mAction表示動做類型,mPointer表示第幾個觸控點。

由於,動做類型只要0-255就能夠了,動做類型,mPointer也是。

只要一個字段(32位),不然須要兩個字段(32*2=64位),便可以節約內存。又能夠方便提升處理速度。

不過一般咱們都是以不一樣的字段來存儲不一樣的信息。可是在計算機內部他們仍是變成了0,1。

計算機始終仍是以位來存儲信息的。若是咱們多我熟悉以位爲基本單位來理解信息的存儲。對於理解android中的不少變量是頗有幫助的。由於他其中的不少東西使用的這樣的節約內在的技巧。

如onMeasure中的MeasureSpec。

   =================== the above is update at 2013-01-24=====

先看關於這兩個方法註釋:

我簡單的翻譯以下:

 

/**
     * action碼的位掩碼部分就是action自己
     */
    public static final int ACTION_MASK             = 0xff;

/**
  返回action的類型,考慮使用getActionMasked()和getActionIndex()來得到單獨的通過掩碼的action和觸控點的索引.
 @return action例如ACTION_DOWN或者ACTION_POINTER_DOWN與轉換的觸控點索引的合成值
     */
    public final int getAction() {
        return mAction;
    }

  /**
   返回通過掩碼的action,沒有觸控點索引信息.
   經過getActionIndex()來獲得觸控操做點的索引.
@return action,例如ACTION_DOWN,ACTION_POINTER_DOWN

 
     */
    public final int getActionMasked() {
        return mAction & ACTION_MASK;
    }

 

在上面的兩個方法中註釋出現差別的地方是對於ACTION_POINTER_DOWN的描述:

經過getAction()返回的ACTION_POINTER_DOWN的是與轉換觸控點索引的合成值.

而getActionMasked()則就是一個ACTION_POINTER_DOWN的值:

 

這麼來看咱們知道一個action的代碼值還包含了action是那個觸控點的索引值:

如今咱們對比來看看ACTION_MASK和ACTION_POINTER_INDEX_MASK

public static final int ACTION_MASK             = 0xff;
public static final int ACTION_POINTER_INDEX_MASK  = 0xff00;
尚未看出來什麼嗎?

您把ACTION_MASK當作是0x00ff

就知道了吧.

也就是說,一個MotionEvent中的action代碼,

前8位是實實在在包含表示哪個動做常量.

後八位呢就是包含了觸控點的索引信息.

由於ACTION_MASK = 0x00ff因此,通過ACTION_MASK掩碼事後的action碼就沒有索引信息了.

如何得索引值呢?

原理:

先將action跟0xff00相與清除前8位用於存儲動做常量的信息,

而後將action右移8位就能夠獲得索引值了.

咱們就能夠本身想辦法獲得索引信息了.

即先對action用ACTION_POINTER_INDEX_MASK進行掩碼處理,

即  maskedIndex = action&ACTION_POINTER_INDEX_MASK = action&0xff00

這各掩碼也就是將action這個數的前8位清零.

而後再將maskedIndex向右移8位就可以獲得索引值了.

再看看android真實是怎麼作的吧,

用於右移8位的常量.

/**
     * Bit shift for the action bits holding the pointer index as
     * defined by {@link #ACTION_POINTER_INDEX_MASK}.
     */
    public static final int ACTION_POINTER_INDEX_SHIFT = 8;

再年獲得索引值方法源代碼,以下:

public final int getActionIndex() {
        return (mAction & ACTION_POINTER_INDEX_MASK) >> ACTION_POINTER_INDEX_SHIFT;
    }

 

爲何要有索引信息?

 由於,這樣說吧,android中,當有觸摸事件發生時(假設已經註冊了事件監聽器),調用你註冊監聽器中的方法onTouch(,MotionEvent ev);傳遞了一個MotionEvent的對象過來.

可是,想一想,上面只傳遞進來一個MotionEvent過來,若是隻是單點觸控那是沒有問題.

問題就是當你多個手指觸控的時候也是隻傳遞這一個MotionEvent進來,

這個時候,你固然想知道每一個手指的所對應的觸控點數據信息啦.

因此MotionEvent中有就要索引信息了.

事件是你能夠很容易經過API看到,MotionEvent還包含了移動操做中其它歷史移動數據.

方便處理觸控的移動操做.

android sdk對於這個類的描述中就有這麼一句:

For efficiency, motion events with ACTION_MOVE may batch together multiple movement samples within a single object.

  我翻譯下:"出於效率的考慮,事件代碼爲ACTION_MOVE的Motion,會在一個MotionEvent對象中包含多個移動數據採樣."

 

如今咱們對於MotionEvent有了初步的瞭解了.

PS:

我發現android4中MotionEvent中的代碼大多變成了原生代碼了:

例如如getX(int)在2.2中是這樣的:

public final float getX(int pointerIndex) {
        return mDataSamples[(pointerIndex*NUM_SAMPLE_DATA) + SAMPLE_X];
    }
但到了4.x是這樣的了:
public final float getX(int pointerIndex) {
        return nativeGetAxisValue(mNativePtr, AXIS_X, pointerIndex, HISTORY_CURRENT);
    }
是否是進步了呢?哈哈!
相關文章
相關標籤/搜索