MotionEvent詳解

Android MotionEvent 詳解,之前用了兩篇文章 事件分發(fā)機(jī)制原理事件分發(fā)機(jī)制詳解 來講解事件分發(fā)蕉鸳,而作為事件分發(fā)主角之一的 MotionEvent 并沒有過多的說明,本文就帶大家了解 MotionEvent 的相關(guān)內(nèi)容,簡要介紹觸摸事件崇败,主要包括 單點(diǎn)觸控远豺、多點(diǎn)觸控、鼠標(biāo)事件 以及 getAction() 和 getActionMasked() 的區(qū)別淮捆。

Android 將所有的輸入事件都放在了 MotionEvent 中郁油,隨著安卓的不斷發(fā)展壯大,MotionEvent 也開始變得越來越復(fù)雜攀痊,下面是我自己整理的 MotionEvent 大事記:

版本號(hào) 更新內(nèi)容
Android 1.0 (API 1 ) 支持單點(diǎn)觸控和軌跡球的事件桐腌。
Android 1.6 (API 4 ) 支持手勢。
Android 2.0 (API 5 ) 支持多點(diǎn)觸控苟径。
Android 3.1 (API 12) 支持觸控筆案站,鼠標(biāo),鍵盤棘街,操縱桿蟆盐,游戲控制器等輸入工具。

以上僅僅是簡要的說明幾次比較大的變動(dòng)遭殉,細(xì)小的修復(fù)和更新不計(jì)其數(shù)石挂,此處就不一一列出了,反正也沒人關(guān)心這些東西险污。
MotionEvent 負(fù)責(zé)集中處理所有類型設(shè)備的輸入事件誊稚,但是由于某些設(shè)備使用的幾率較小本文會(huì)忽略講解,或者簡要講解罗心,例如:
1里伯、軌跡球只出現(xiàn)在最早的設(shè)備上,現(xiàn)代的設(shè)備上已經(jīng)見不到了渤闷,本文不再敘述疾瓮。
2、觸控筆和手指處理流程基本相同飒箭,不再多說狼电。
3蜒灰、鼠標(biāo)在手機(jī)上使用概率也比較小,會(huì)在文末簡要介紹肩碟。

單點(diǎn)觸控

單點(diǎn)觸控就非常簡單啦强窖,入門的工程師都會(huì)用,上一篇文章也簡要介紹過削祈,主要涉及以下幾個(gè)事件:

事件 簡介
ACTION_DOWN 手指 初次接觸到屏幕 時(shí)觸發(fā)翅溺。
ACTION_MOVE 手指 在屏幕上滑動(dòng) 時(shí)觸發(fā),會(huì)多次觸發(fā)髓抑。
ACTION_UP 手指 離開屏幕 時(shí)觸發(fā)咙崎。
ACTION_CANCEL 事件 被上層攔截 時(shí)觸發(fā)。
ACTION_OUTSIDE 手指 不在控件區(qū)域 時(shí)觸發(fā)吨拍。

和以下的幾個(gè)方法:

方法 簡介
getAction() 獲取事件類型褪猛。
getX() 獲得觸摸點(diǎn)在當(dāng)前 View 的 X 軸坐標(biāo)。
getY() 獲得觸摸點(diǎn)在當(dāng)前 View 的 Y 軸坐標(biāo)羹饰。
getRawX() 獲得觸摸點(diǎn)在整個(gè)屏幕的 X 軸坐標(biāo)伊滋。
getRawY() 獲得觸摸點(diǎn)在整個(gè)屏幕的 Y 軸坐標(biāo)。

關(guān)于 getgetRaw 的區(qū)別可以參考這一篇文章 安卓自定義View基礎(chǔ)-坐標(biāo)系

單點(diǎn)觸控一次簡單的交互流程是這樣的:

手指落下(ACTION_DOWN) -> 多次移動(dòng)(ACTION_MOVE) -> 離開(ACTION_UP)

  • 本次事例中 ACTION_MOVE 有多次觸發(fā)队秩。
  • 如果僅僅是單擊(手指按下再抬起)新啼,不會(huì)觸發(fā) ACTION_MOVE。
單指觸摸事件.gif

針對單點(diǎn)觸控的事件處理一般是這樣寫的:

@Override
public boolean onTouchEvent(MotionEvent event) {
    // ▼ 注意這里使用的是 getAction()刹碾,先埋一個(gè)小尾巴燥撞。
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            // 手指按下
            break;
        case MotionEvent.ACTION_MOVE:
            // 手指移動(dòng)
            break;
        case MotionEvent.ACTION_UP:
            // 手指抬起
            break;
        case MotionEvent.ACTION_CANCEL:
            // 事件被攔截 
            break;
        case MotionEvent.ACTION_OUTSIDE:
            // 超出區(qū)域 
            break;
    }
    return super.onTouchEvent(event);
}

相信小伙伴對此已經(jīng)非常熟悉了,經(jīng)常使用的東西迷帜,我也不啰嗦了物舒。

但其中有兩個(gè)比較特殊的事件: ACTION_CANCELACTION_OUTSIDE
為什么說特殊呢戏锹,因?yàn)樗鼈兪怯沙绦蛴|發(fā)而產(chǎn)生的冠胯,而且觸發(fā)條件也非常特殊,通常情況下即便不處理這兩個(gè)事件也沒有什么問題锦针。接下來我們就扒一扒它們的真面目:

ACTION_CANCEL

ACTION_CANCEL 的觸發(fā)條件是事件被上層攔截荠察,然而我們在 事件分發(fā)機(jī)制原理 一文中了解到當(dāng)事件被上層 View 攔截的時(shí)候,ChildView 是收不到任何事件的奈搜,ChildView 收不到任何事件悉盆,自然也不會(huì)收到 ACTION_CANCEL 了,所以說這個(gè) ACTION_CANCEL 的正確觸發(fā)條件并不是這樣馋吗,那么是什么呢焕盟?

事實(shí)上,只有上層 View 回收事件處理權(quán)的時(shí)候宏粤,ChildView 才會(huì)收到一個(gè) ACTION_CANCEL 事件脚翘。

這樣說可能不太容易理解灼卢,咱舉個(gè)例子?

舉例子.png

例如:上層 View 是一個(gè) RecyclerView,它收到了一個(gè) ACTION_DOWN 事件来农,由于這個(gè)可能是點(diǎn)擊事件鞋真,所以它先傳遞給對應(yīng) ItemView,詢問 ItemView 是否需要這個(gè)事件沃于,然而接下來又傳遞過來了一個(gè) ACTION_MOVE 事件涩咖,且移動(dòng)的方向和 RecyclerView 的可滑動(dòng)方向一致,所以 RecyclerView 判斷這個(gè)事件是滾動(dòng)事件揽涮,于是要收回事件處理權(quán),這時(shí)候?qū)?yīng)的 ItemView 會(huì)收到一個(gè) ACTION_CANCEL 饿肺,并且不會(huì)再收到后續(xù)事件蒋困。

通俗一點(diǎn)?

RecyclerView:兒砸敬辣,這里有一個(gè) ACTION_DOWN 你看你要不要雪标。
ItemView :好嘞,我看看溉跃。
RecyclerView:噫村刨?居然是移動(dòng)事件ACTION_MOVE,我要滾起來了撰茎,兒砸嵌牺,我可能要把你送去你姑父家(緩存區(qū))了,在這之前給你一個(gè) ACTION_CANCEL龄糊,你要收好啊逆粹。
ItemView :……

這是實(shí)際開發(fā)中最有可能見到 ACTION_CANCEL 的場景了。

ACTION_OUTSIDE

ACTION_OUTSIDE的觸發(fā)條件更加奇葩炫惩,從字面上看僻弹,outside 意思不就是超出區(qū)域么?然而不論你如何滑動(dòng)超出控件區(qū)域都不會(huì)觸發(fā) ACTION_OUTSIDE 這個(gè)事件他嚷。相信很多魔法師都對此很是疑惑蹋绽,說好的超出區(qū)域呢?

實(shí)際上這個(gè)事件根本就不是在這里用的筋蓖,看官方解釋(裝一下逼):

A movement has happened outside of the normal bounds of the UI element. This does not provide a full gesture, but only the initial location of the movement/touch.

一個(gè)觸摸事件已經(jīng)發(fā)生了UI元素的正常范圍之外卸耘。因此不再提供完整的手勢,只提供 運(yùn)動(dòng)/觸摸 的初始位置粘咖。

我們知道鹊奖,正常情況下,如果初始點(diǎn)擊位置在該視圖區(qū)域之外涂炎,該視圖根本不可能會(huì)收到事件忠聚,然而设哗,萬事萬物都不是絕對的,肯定還有一些特殊情況两蟀,你可曾還記得點(diǎn)擊 Dialog 區(qū)域外關(guān)閉嗎网梢?Dialog 就是一個(gè)特殊的視圖(沒有占滿屏幕大小的窗口),能夠接收到視圖區(qū)域外的事件(雖然在通常情況下你根本用不到這個(gè)事件)赂毯,除了 Dialog 之外战虏,你最可能看到這個(gè)事件的場景是懸浮窗,當(dāng)然啦党涕,想要接收到視圖之外的事件需要一些特殊的設(shè)置烦感。

設(shè)置視圖的 WindowManager 布局參數(shù)的 flags為FLAG_WATCH_OUTSIDE_TOUCH,這樣點(diǎn)擊事件發(fā)生在這個(gè)視圖之外時(shí)膛堤,該視圖就可以接收到一個(gè) ACTION_OUTSIDE 事件手趣。

參見StackOverflow:How to dismiss the dialog with click on outside of the dialog?

由于這個(gè)事件用到的幾率比較小,此處就不展開敘述了肥荔,以后用到的時(shí)候再詳細(xì)講解绿渣。

多點(diǎn)觸控

Android 在 2.0 版本的時(shí)候開始支持多點(diǎn)觸控,一旦出現(xiàn)了多點(diǎn)觸控燕耿,很多東西就突然之間變得麻煩起來了中符,首先要解決的問題就是 多個(gè)手指同時(shí)按在屏幕上,會(huì)產(chǎn)生很多的事件誉帅,這些事件該如何區(qū)分呢淀散?

為了區(qū)分這些事件,工程師們用了一個(gè)很簡單的辦法--編號(hào)蚜锨,當(dāng)手指第一次按下時(shí)產(chǎn)生一個(gè)唯一的號(hào)碼吧凉,手指抬起或者事件被攔截就回收編號(hào),就這么簡單踏志。

第一次按下的手指特殊處理作為主指針阀捅,之后按下的手指作為輔助指針,然后隨之衍生出來了以下事件(注意增加的事件和事件簡介的變化):

事件 簡介
ACTION_DOWN 第一個(gè) 手指 初次接觸到屏幕 時(shí)觸發(fā)针余。
ACTION_MOVE 手指 在屏幕上滑動(dòng) 時(shí)觸發(fā)饲鄙,會(huì)多次觸發(fā)。
ACTION_UP 最后一個(gè) 手指 離開屏幕 時(shí)觸發(fā)圆雁。
ACTION_POINTER_DOWN 有非主要的手指按下(即按下之前已經(jīng)有手指在屏幕上)忍级。
ACTION_POINTER_UP 有非主要的手指抬起(即抬起之后仍然有手指在屏幕上)。
以下事件類型不推薦使用 ------------------
ACTION_POINTER_1_DOWN 第 2 個(gè)手指按下伪朽,已廢棄轴咱,不推薦使用。
ACTION_POINTER_2_DOWN 第 3 個(gè)手指按下,已廢棄朴肺,不推薦使用窖剑。
ACTION_POINTER_3_DOWN 第 4 個(gè)手指按下,已廢棄戈稿,不推薦使用西土。
ACTION_POINTER_1_UP 第 2 個(gè)手指抬起,已廢棄鞍盗,不推薦使用需了。
ACTION_POINTER_2_UP 第 3 個(gè)手指抬起,已廢棄般甲,不推薦使用肋乍。
ACTION_POINTER_3_UP 第 4 個(gè)手指抬起,已廢棄敷存,不推薦使用墓造。

和以下方法:

方法 簡介
getActionMasked() getAction() 類似,多點(diǎn)觸控必須使用這個(gè)方法獲取事件類型历帚。
getActionIndex() 獲取該事件是哪個(gè)指針(手指)產(chǎn)生的滔岳。
getPointerCount() 獲取在屏幕上手指的個(gè)數(shù)杠娱。
getPointerId(int pointerIndex) 獲取一個(gè)指針(手指)的唯一標(biāo)識(shí)符ID挽牢,在手指按下和抬起之間ID始終不變。
findPointerIndex(int pointerId) 通過PointerId獲取到當(dāng)前狀態(tài)下PointIndex摊求,之后通過PointIndex獲取其他內(nèi)容禽拔。
getX(int pointerIndex) 獲取某一個(gè)指針(手指)的X坐標(biāo)
getY(int pointerIndex) 獲取某一個(gè)指針(手指)的Y坐標(biāo)

由于多點(diǎn)觸控部分涉及內(nèi)容比較多,也很復(fù)雜室叉,我準(zhǔn)備單獨(dú)用一篇文章進(jìn)行詳細(xì)敘述睹栖,所以這里只敘述一些基礎(chǔ)的內(nèi)容作為鋪墊:

getAction() 與 getActionMasked()

當(dāng)多個(gè)手指在屏幕上按下的時(shí)候,會(huì)產(chǎn)生大量的事件茧痕,如何在獲取事件類型的同時(shí)區(qū)分這些事件就是一個(gè)大問題了野来。

一般來說我們可以通過為事件添加一個(gè)int類型的index屬性來區(qū)分,但是我們知道谷歌工程師是有潔癖的(在 自定義View分類與流程 的onMeasure中已經(jīng)見識(shí)過了)踪旷,為了添加一個(gè)通常數(shù)值不會(huì)超過10的index屬性就浪費(fèi)一個(gè)int大小的空間簡直是不能忍受的曼氛,于是工程師們將這個(gè)index屬性和事件類型直接合并了。

int類型共32位(0x00000000)令野,他們用最低8位(0x000000ff)表示事件類型舀患,再往前的8位(0x0000ff00)表示事件編號(hào),以手指按下為例講解數(shù)值是如何合成的:

ACTION_DOWN 的默認(rèn)數(shù)值為 (0x00000000)
ACTION_POINTER_DOWN 的默認(rèn)數(shù)值為 (0x00000005)

手指按下 觸發(fā)事件(數(shù)值)
第1個(gè)手指按下 ACTION_DOWN (0x00000000)
第2個(gè)手指按下 ACTION_POINTER_DOWN (0x00000105)
第3個(gè)手指按下 ACTION_POINTER_DOWN (0x00000205)
第4個(gè)手指按下 ACTION_POINTER_DOWN (0x00000305)

注意:
上面表格中用粗體標(biāo)示出的數(shù)值气破,可以看到隨著按下手指數(shù)量的增加聊浅,這個(gè)數(shù)值也是一直變化的,進(jìn)而導(dǎo)致我們使用 getAction() 獲取到的數(shù)值無法與標(biāo)準(zhǔn)的事件類型進(jìn)行對比,為了解決這個(gè)問題低匙,他們創(chuàng)建了一個(gè) getActionMasked() 方法旷痕,這個(gè)方法可以清除index數(shù)值,讓其變成一個(gè)標(biāo)準(zhǔn)的事件類型努咐。
1苦蒿、多點(diǎn)觸控時(shí)必須使用 getActionMasked() 來獲取事件類型。
2渗稍、單點(diǎn)觸控時(shí)由于事件數(shù)值不變佩迟,使用 getAction()getActionMasked() 兩個(gè)方法都可以。
3竿屹、使用 getActionIndex() 可以獲取到這個(gè)index數(shù)值报强。不過請注意,getActionIndex() 只在 down 和 up 時(shí)有效拱燃,move 時(shí)是無效的秉溉。

目前來說獲取事件類型使用 getActionMasked() 就行了,但是如果一定要編譯時(shí)兼容古董版本的話碗誉,可以考慮使用這樣的寫法:

final int action = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO)
                ? event.getActionMasked()
                : event.getAction();
switch (action){
    case MotionEvent.ACTION_DOWN:
        // TODO
        break;
}

PointId

雖然前面剛剛說了一個(gè) actionIndex召嘶,可以使用 getActionIndex() 獲得,但通過 actionIndex 字面意思知道哮缺,這個(gè)只表示事件的序號(hào)弄跌,而且根據(jù)其說明文檔解釋,這個(gè) ActionIndex 只有在手指按下(down)和抬起(up)時(shí)是有用的尝苇,在移動(dòng)(move)時(shí)是沒有用的铛只,事件追蹤非常重要的一環(huán)就是移動(dòng)(move),然而它卻沒卵用糠溜,這也太不實(shí)在了 ( ̄Д ̄)?

鄭重聲明:追蹤事件流淳玩,請認(rèn)準(zhǔn) PointId,這是唯一官方指定標(biāo)準(zhǔn)非竿,不要相信 ActionIndex 那個(gè)小婊砸蜕着。

PointId 在手指按下時(shí)產(chǎn)生,手指抬起或者事件被取消后消失红柱,是一個(gè)事件流程中唯一不變的標(biāo)識(shí)承匣,可以在手指按下時(shí) 通過 getPointerId(int pointerIndex) 獲得。 (參數(shù)中的 pointerIndex 就是 actionIndex)

關(guān)于事件流的追蹤等問題在講解多點(diǎn)觸控時(shí)再詳細(xì)講解豹芯。

歷史數(shù)據(jù)(批處理)

由于我們的設(shè)備非常靈敏悄雅,手指稍微移動(dòng)一下就會(huì)產(chǎn)生一個(gè)移動(dòng)事件,所以移動(dòng)事件會(huì)產(chǎn)生的特別頻繁铁蹈,為了提高效率宽闲,系統(tǒng)會(huì)將近期的多個(gè)移動(dòng)事件(move)按照事件發(fā)生的順序進(jìn)行排序打包放在同一個(gè) MotionEvent 中众眨,與之對應(yīng)的產(chǎn)生了以下方法:

事件 簡介
getHistorySize() 獲取歷史事件集合大小
getHistoricalX(int pos) 獲取第pos個(gè)歷史事件x坐標(biāo)
(pos < getHistorySize())
getHistoricalY(int pos) 獲取第pos個(gè)歷史事件y坐標(biāo)
(pos < getHistorySize())
getHistoricalX (int pin, int pos) 獲取第pin個(gè)手指的第pos個(gè)歷史事件x坐標(biāo)
(pin < getPointerCount(), pos < getHistorySize() )
getHistoricalY (int pin, int pos) 獲取第pin個(gè)手指的第pos個(gè)歷史事件y坐標(biāo)
(pin < getPointerCount(), pos < getHistorySize() )

注意:

  1. pin 全稱是 pointerIndex,表示第幾個(gè)手指容诬,此處為了節(jié)省空間使用了縮寫娩梨。
  2. 歷史數(shù)據(jù)只有 ACTION_MOVE 事件。
  3. 歷史數(shù)據(jù)單點(diǎn)觸控和多點(diǎn)觸控均可以用览徒。

下面是官方文檔給出的一個(gè)簡單使用示例:

void printSamples(MotionEvent ev) {
     final int historySize = ev.getHistorySize();
     final int pointerCount = ev.getPointerCount();
     for (int h = 0; h < historySize; h++) {
         System.out.printf("At time %d:", ev.getHistoricalEventTime(h));
         for (int p = 0; p < pointerCount; p++) {
             System.out.printf("  pointer %d: (%f,%f)",
                 ev.getPointerId(p), ev.getHistoricalX(p, h), ev.getHistoricalY(p, h));
         }
     }
     System.out.printf("At time %d:", ev.getEventTime());
     for (int p = 0; p < pointerCount; p++) {
         System.out.printf("  pointer %d: (%f,%f)",
             ev.getPointerId(p), ev.getX(p), ev.getY(p));
     }
}

獲取事件發(fā)生的時(shí)間

獲取事件發(fā)生的時(shí)間狈定。

方法 簡介
getDownTime() 獲取手指按下時(shí)的時(shí)間。
getEventTime() 獲取當(dāng)前事件發(fā)生的時(shí)間习蓬。
getHistoricalEventTime(int pos) 獲取歷史事件發(fā)生的時(shí)間纽什。
  1. pos 表示歷史數(shù)據(jù)中的第幾個(gè)數(shù)據(jù)。( pos < getHistorySize() )
  2. 返回值類型為 long躲叼,單位是毫秒芦缰。

獲取壓力(接觸面積大小)

MotionEvent支持獲取某些輸入設(shè)備(手指或觸控筆)的與屏幕的接觸面積和壓力大小,主要有以下方法:

描述中使用了手指枫慷,觸控筆也是一樣的让蕾。

方法 簡介
getSize () 獲取第1個(gè)手指與屏幕接觸面積的大小
getSize (int pin) 獲取第pin個(gè)手指與屏幕接觸面積的大小
getHistoricalSize (int pos) 獲取歷史數(shù)據(jù)中第1個(gè)手指在第pos次事件中的接觸面積
getHistoricalSize (int pin, int pos) 獲取歷史數(shù)據(jù)中第pin個(gè)手指在第pos次事件中的接觸面積
getPressure () 獲取第一個(gè)手指的壓力大小
getPressure (int pin) 獲取第pin個(gè)手指的壓力大小
getHistoricalPressure (int pos) 獲取歷史數(shù)據(jù)中第1個(gè)手指在第pos次事件中的壓力大小
getHistoricalPressure (int pin, int pos) 獲取歷史數(shù)據(jù)中第pin個(gè)手指在第pos次事件中的壓力大小
  1. pin 全稱是 pointerIndex,表示第幾個(gè)手指或听。(pin < getPointerCount() )
  2. pos 表示歷史數(shù)據(jù)中的第幾個(gè)數(shù)據(jù)探孝。( pos < getHistorySize() )

注意:

1、獲取接觸面積大小和獲取壓力大小是需要硬件支持的誉裆。
2顿颅、非常不幸的是大部分設(shè)備所使用的電容屏不支持壓力檢測,但能夠大致檢測出接觸面積找御。
3元镀、大部分設(shè)備的 getPressure() 是使用接觸面積來模擬的绍填。
4霎桅、由于某些未知的原因(可能系統(tǒng)版本和硬件問題),某些設(shè)備不支持該方法讨永。

我用不同的設(shè)備對這兩個(gè)方法進(jìn)行了測試滔驶,然而不同設(shè)備測試出來的結(jié)果不相同,之后經(jīng)過我多方查證卿闹,發(fā)現(xiàn)是系統(tǒng)問題揭糕,有的設(shè)備上只有 getSize() 能用,有的設(shè)備上只有 getPressure() 能用锻霎,而有的則兩個(gè)都不能用著角。

由于獲取接觸面積和獲取壓力大小受系統(tǒng)和硬件影響,使用的時(shí)候一定要進(jìn)行數(shù)據(jù)檢測旋恼,以防因?yàn)樵O(shè)備問題而導(dǎo)致程序出錯(cuò)吏口。

鼠標(biāo)事件

由于觸控筆事件和手指事件處理流程大致相同,所以就不講解了,這里講解一下與鼠標(biāo)相關(guān)的幾個(gè)事件:

事件 簡介
ACTION_HOVER_ENTER 指針移入到窗口或者View區(qū)域产徊,但沒有按下昂勒。
ACTION_HOVER_MOVE 指針在窗口或者View區(qū)域移動(dòng),但沒有按下舟铜。
ACTION_HOVER_EXIT 指針移出到窗口或者View區(qū)域戈盈,但沒有按下。
ACTION_SCROLL 滾輪滾動(dòng)谆刨,可以觸發(fā)水平滾動(dòng)(AXIS_HSCROLL)或者垂直滾動(dòng)(AXIS_VSCROLL)

注意:

1塘娶、這些事件類型是 安卓4.0 (API 14) 才添加的。
2痊夭、使用 getActionMasked() 獲得這些事件類型血柳。
3、這些事件不會(huì)傳遞到 onTouchEvent(MotionEvent) 而是傳遞到 onGenericMotionEvent(MotionEvent) 生兆。

輸入設(shè)備類型判斷

輸入設(shè)備類型判斷也是安卓4.0 (API 14) 才添加的难捌,主要包括以下幾種設(shè)備:

設(shè)備類型 簡介
TOOL_TYPE_ERASER 橡皮擦
TOOL_TYPE_FINGER 手指
TOOL_TYPE_MOUSE 鼠標(biāo)
TOOL_TYPE_STYLUS 手寫筆
TOOL_TYPE_UNKNOWN 未知類型

使用 getToolType(int pointerIndex) 來獲取對應(yīng)的輸入設(shè)備類型,pointIndex可以為0鸦难,但必須小于 getPointerCount()根吁。

文章搬運(yùn)自 安卓自定義View進(jìn)階-MotionEvent詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市合蔽,隨后出現(xiàn)的幾起案子击敌,更是在濱河造成了極大的恐慌,老刑警劉巖拴事,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沃斤,死亡現(xiàn)場離奇詭異,居然都是意外死亡刃宵,警方通過查閱死者的電腦和手機(jī)衡瓶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牲证,“玉大人哮针,你說我怎么就攤上這事√古郏” “怎么了十厢?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捂齐。 經(jīng)常有香客問我蛮放,道長,這世上最難降的妖魔是什么奠宜? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任包颁,我火速辦了婚禮缝其,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘徘六。我一直安慰自己内边,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布待锈。 她就那樣靜靜地躺著漠其,像睡著了一般。 火紅的嫁衣襯著肌膚如雪竿音。 梳的紋絲不亂的頭發(fā)上和屎,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機(jī)與錄音春瞬,去河邊找鬼柴信。 笑死,一個(gè)胖子當(dāng)著我的面吹牛宽气,可吹牛的內(nèi)容都是我干的随常。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼萄涯,長吁一口氣:“原來是場噩夢啊……” “哼绪氛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起涝影,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤枣察,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后燃逻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體序目,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年伯襟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猿涨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逗旁,死狀恐怖嘿辟,靈堂內(nèi)的尸體忽然破棺而出舆瘪,到底是詐尸還是另有隱情片效,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布英古,位于F島的核電站淀衣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏召调。R本人自食惡果不足惜膨桥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一蛮浑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧只嚣,春花似錦沮稚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至调鲸,卻和暖如春盛杰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背藐石。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工即供, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人于微。 一個(gè)月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓逗嫡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親株依。 傳聞我的和親對象是個(gè)殘疾皇子祸穷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評論 2 348