九九99精品-九九99靖品-九九99九九视频在线观看-九九99九九在线精品视频-曰韩一级-曰韩一级毛片

Android觸摸事件的響應機制

作者: Touchscreen     時間:2015-06-17     源于:科技快報    總點擊:
【導讀】:在用戶的一次單手指觸摸屏幕過程中,簡單的講,會按順序產生一個ACTION_DOWN,若干個ACTION_MOVE,和一個ACTION_UP,我們下面的討論也會基于這個簡單case。

    北京時間06月17日消息,中國觸摸屏網訊,用戶觸摸屏幕所產生的Touch Event在Android里是用一個MotionEvent對象來傳遞和處理的,我們最關注的是MotionEvent里的action,可以看到有ACTION_DOWN, ACTION_UP,ACTION_MOVE,ACTION_CANCEL,ACTION_POINTER_DOWN,ACTION_POINTER_UP等等很多種,在這里面最需要關注的是ACTION_DOWN和ACTION_UP,它們一個代表了用戶按壓動作的開始,一個代表了用戶按壓動作的結束,其他的一些ACTION基本都是發生在這2個ACTION之間的(ACTION_CANCEL等特殊的暫不討論)。

    本文來自:http://www.zc28898.cn/touchscreen/news/front/201506/17-36507.html

在用戶的一次單手指觸摸屏幕過程中,簡單的講,會按順序產生一個ACTION_DOWN,若干個ACTION_MOVE,和一個ACTION_UP,我們下面的討論也會基于這個簡單case。

觸摸事件的傳遞處理順序

一個觸摸事件首先是在硬件層面觸發,然后逐層傳遞到軟件直至我們的app,前面的細節一般來說不用了解,我們討論的事件入口從Activity開始。

籠統的說(實際上細節有所不同,下面會提到)

觸摸事件的傳遞順序是:

Activity -> 當前活動窗口(PhoneWindow) -> 窗口的Top-Level View(DecorView) -> 各級ViewGroup (如各種Layout) -> ... -> 各級ViewGroup -> 葉子節點 View

而觸摸事件的處理順序則剛好相反:

葉子節點 View -> 各級ViewGroup -> ... -> 各級ViewGroup -> (Window和DecorView只有分發沒有處理) -> Activity

當葉子節點View接受到事件之后,會試圖做出處理,如果它處理了,則上面各層不再處理,如果它沒有處理則往上由它的父ViewGroup處理,這樣逐層向上按順序試圖處理,直到Activity。

分發和處理的關鍵函數

從上面籠統提到的事件分發處理順序可以看到,關鍵的分發處理集中在Activity,ViewGroup和View中,那么對于它們來說,有如下幾個分發和處理的關鍵函數,這里先做一個簡單介紹,后續再做詳細說明。

1,boolean dispatchTouchEvent(MotionEvent event)

這個函數是最關鍵的分發處理函數,里面既包含了分發的邏輯,又包含了對處理的邏輯調用

分發邏輯:這個函數會先調用子view的dispatchTouchEvent進行分發

處理邏輯:如果子view沒有對事件進行消化處理的話,這個函數就會調用本UI組件的處理函數如onTouchEvent

函數返回值表示這個觸摸事件是否被當前這個UI組件(Activity/ViewGroup/View)消化處理了

2,boolean onTouchEvent(MotionEvent event)

這個函數是UI組件自己實現用來響應處理觸摸事件的

函數返回值表示這個觸摸事件是否被當前這個UI組件(Activity/ViewGroup/View)消化處理了

3,View.OnTouchListener: boolean onTouch(View v, MotionEvent event)

這個函數不是Activity/ViewGroup/View本身的響應處理函數,而是一個Listener的響應處理函數

需要給View通過setOnTouchListener來設置Listener以使得這個onTouch函數能夠起作用

Activity沒有setOnTouchListener

函數返回值表示這個觸摸事件是否被當前這個UI組件(Activity/ViewGroup/View)消化處理了

4,ViewGroup: boolean onInterceptTouchEvent(MotionEvent event)

這個函數表明是否要攔截這個事件,前面提到過事件的分發順序是在View tress里從根到葉子逐層分發,處理則是反向的從葉子到根逐層處理,onInterceptTouchEvent如果返回true,則表示我這一層要攔截這個事件自己進行處理了,不要把它分發到子View里

這個函數只有ViewGroup含有,View沒有,因為View已經是葉子節點了,沒有子View了

這個函數默認是返回false的,一般不要輕易override它,因為常規來講是應該由子View先響應處理的

分發和處理的細節流程

ACTION_DOWN的處理

前面說過ACTION_DOWN是一個觸摸動作的起始,所以對ACTION_DOWN的處理和對其他事件的處理在細節上是有不同的,各個UI組件對于ACTION_DOWN事件的處理流程可以看到如下:

(注意這里 view 表示一個視圖組件,它可以是一個 View 也可以是一個 ViewGroup)

Activity -> dispatchTouchEvent:

通過getWindow().superDispatchTouchEvent(event)把事件分發到當前活動窗口(PhoneWindow),之后是 窗口的Top-Level View(DecorView),調用了DecorView的dispatchTouchEvent,DecorView繼承自ViewGroup,所以這里實際上就進入了ViewGroup層面的dispatchTouchEvent

如果superDispatchTouchEvent最終返回true(即下層的某個ViewGroup或者View消化處理了該函數,dispatchTouchEvent返回true),則直接返回

如果返回值為false,則調用Activity的onTouchEvent對事件進行處理

ViewGroup -> dispatchTouchEvent:

首先是檢查本view里是否保存了一個motion target(步驟4提到了怎么設置motion target),如果有則清除它

然后是調用onInterceptTouchEvent看這個事件是否需要被自己攔截,如果返回true,則直接進入步驟7開始自己處理事件的流程

如果返回false,則需要遍歷所有的子view,遍歷的順序是:

首先按照Z-order

在同一Z值下如果可以的話按照子view的drawing order,這里的drawing order需要ViewGroup的子類override了getChildDrawingOrder才會實際生效

遍歷子view的時候,如果這個觸摸事件發生的位置在這個view的視覺范圍以內,那么就調用child.dispatchTouchEvent將事件分發給這個子view,如果這個子view消化處理了這個事件(即dispatchTouchEvent返回true),本view會將該子view賦值給一個表明motion target的變量,且此時跳出循環

循環遍歷結束后,如果有子view處理了該事件(即motion target不為空),則返回true表明此事件已經被處理

如果沒有任何一個子view處理了該事件(即motion target不為空),則本view需要進行處理,進入步驟6

查看當前view是否注冊了OnTouchListener,如果有,則調用該listener的onTouch函數來處理事件,如果onTouch返回true表示消化處理了該事件,則直接返回true

如果onTouch返回false表示沒有處理,則繼續調用本view的onTouchEvent函數來處理事件,這里會返回onTouchEvent的返回值

View -> dispatchTouchEvent:

查看當前view是否注冊了OnTouchListener,如果有,則調用該listener的onTouch函數來處理事件,如果onTouch返回true表示消化處理了該事件,則直接返回true

如果onTouch返回false表示沒有處理,則繼續調用本view的onTouchEvent函數來處理事件,這里會返回onTouchEvent的返回值

其他ACTION的處理

上面說了ACTION_DOWN的處理,那ACTION_DOWN后續的ACTION_MOVE,ACTION_UP之類的事件又是怎么處理的呢?它們的處理方式略有不同:

在Activity層面來看,它們的處理和ACTION_DOWN沒有區別。

在ViewGroup層面來看,處理開始有了差異:

ViewGroup -> dispatchTouchEvent:

檢查當前view在之前處理ACTION_DOWN(ACTION_MOVE,ACTION_UP之類的事件一定是有一個配對的ACTION_DOWN事件在前面發生)的時候是否已經設置了一個motion target

如果有這個target,那么表明之前的ACTION_DOWN事件就是由該子view處理的,此時直接調用motion_target.dispatchTouchEvent

如果沒有這個target,那么表明之前的ACTION_DOWN沒有任何一個子view處理,那么后續這些事件也不要發給子view了,直接自己處理,進入步驟4

查看當前view是否注冊了OnTouchListener,如果有,則調用該listener的onTouch函數來處理事件,如果onTouch返回true表示消化處理了該事件,則直接返回true

如果onTouch返回false表示沒有處理,則繼續調用本view的onTouchEvent函數來處理事件,這里會返回onTouchEvent的返回值

注意整個流程中都跳過了onInterceptTouchEvent的攔截

在View層面來看,處理方式也是一樣的。

所以這里可以看到的現象就是:ACTION_DOWN被誰處理了,后續的ACTION_MOVE,ACTION_UP等事件最終也會交由誰處理。

onTouchEvent() or OnTouchListener.onTouch()?

從上面的內容可以看出來,我們要想對一個觸摸事件進行響應,可以在view的onTouchEvent()函數里處理,也可以給view設置一個OnTouchListener然后在listener的onTouch()函數里處理,那么它們有些什么區別?我們應該怎么選擇呢?

首先看區別:

onTouchEvent()是View自己的函數,對于我們來說無法override 各種View或者ViewGroup的onTouchEvent()函數,只能是在自己自定義的view里面實現override;而OnTouchListener的onTouch()是可以對任何View/ViewGroup起作用的,我們只需要在代碼里為該View/ViewGroup加一個listener就行

OnTouchListener的onTouch()的執行順序在view的onTouchEvent()之前,如果在onTouch()函數里面響應完了觸摸事件并返回true之后,onTouchEvent()是不會被調用的

知道了區別,那么我們就可以輕易的做出選擇了(只是一家之言,歡迎各種不同意見):

OnTouchListener的onTouch()基本上是萬能的,任何時候都可以用它,所以大部分時候直接用它就行了

在自定義view里面,如果出于代碼結構和功能清晰的目的,可以使用onTouchEvent()

 


    觸摸屏與OLED網推出微信公共平臺,每日一條微信新聞,涵蓋觸摸屏材料、觸摸屏設備、觸控面板行業主要資訊,第一時間了解觸摸屏行業發展動態。關注辦法:微信公眾號“i51touch” 或微信中掃描下面二維碼關注,或這里查看詳細步驟
相關閱讀:3D打印    模具產業    微鑄鍛技術    石墨烯    OLED面板    夏普    iPhone 8    半導體    蘋果    
關于我們 | 廣告服務 | 聯系我們 | 版權聲明 | 隱私政策 | 網站地圖 | 友情鏈接 | 歡迎投稿 | 加入收藏 | 意見反饋 | 經銷商加入
網站廣告、經銷商加盟、觸摸屏軟件銷售: 028-85108892 13183843395 028-66219290 聯系人: 張小姐 產品購買聯系方式如下:
地址:成都市高升橋東路2號高盛中心1109室 電話: 028-85108892 13183843395 028-66219290
版權所有 Copyright(C) 2003-2015 All rights reserved 中國觸摸屏網 電子郵件: 51touch@126.com touch8@gmail.com
業務合作QQ:觸摸屏技術,觸摸屏報價,觸摸屏軟件咨詢 43361182 觸摸屏軟件制作與技術支持:觸摸屏軟件,觸摸查詢系統,觸摸查詢軟件 893008608 媒體合作QQ: 893008608

2000人超級QQ觸摸屏群:59897879 171220106


分享到