Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android亂侃觸摸事件傳遞

Android亂侃觸摸事件傳遞

編輯:關於Android編程

講解觸摸事件傳遞原理的網上有一大把,有從源碼角度講的,有從實際例子角度講的。我這裡呢只是記錄下自己的理解,講的可能沒其他大牛透徹,有錯誤的跪求評論指正。

 

直接上圖,對照圖解和文字來分析觸摸事件的傳遞。

 

(1)亂七八糟圖解版:

(2)看圖說話:

 

(2.1)上圖並不包含Activity,Activity沒有onInterceptTouchEvent方法,默認實現都是直接往下傳遞。

 

(2.2)講解3個觸摸事件控制方法的含義及其返回值的意義:

 

<1>onInterceptTouchEvent

onInterceptTouchEvent是ViewGroup特有的方法,Activity和View並沒有此方法,它的作用是用於攔截觸摸事件不再傳遞給子View(Activity和View並沒有子View,所以沒有此方法很符合邏輯),默認實現不攔截。如果攔截的話子View將完全接受不到觸摸事件,子View的任何相關觸摸事件的方法都不會被調用。(注:有例外情況我會在後面再說)(有特殊情況)

返回true:
表示攔截觸摸事件,不繼續調用子View的dispatchTouchEvent方法,直接調用自己的onTouchEvent方法。(有特殊情況)

返回false:
表示不攔截事件,繼續去調用子View的dispatchTouchEvent。

 

<2>dispatchTouchEvent

用於分派觸摸事件,注意是分派事件,而不是處理事件,這個方法應該做的是決定事件的傳遞方向,而不是處理消費掉觸摸事件。

返回true:

表示自己要消費這個事件,但並不是馬上消費,而是如果其子View沒人消費的話,則自己消費。事件還是會繼續往下傳遞的,只是在往上傳遞過程中如果還能到達自己的話,那麼就會去消費這個事件。

返回false:

表示自己不消費這個事件,如果同時onTouchEvent也返回false表示不消費這個事件的話,就會繼續往上傳遞給parent的onTouchEvent。

 

<3>onTouchEvent

用於處理事件,如果你想處理觸摸事件並做出相應的動作,那麼應該在這個方法中進行。

返回true:

表示自己想消費這個事件,並且馬上生效,即刻消費,事件傳遞停止。

返回false:

表示自己不想消費這個事件,同時檢查dispatchTouchEvent之前若是返回了true,就會發現:哎呀,我之前說子View沒人處理的話,那麼就我來處理。好吧,我要遵守諾言,就交給我處理吧,不要再傳遞了。

 

注意dispatchTouchEvent和onTouchEvent返回true的區別:

 

dispatchTouchEvent是沒人消費的話就交給我消費,你們都沒人要啊,那就給我吧,各位大爺真是好人啊。


onTouchEvent是我現在就要消費,其它人都沒份了,都干嘛干嘛去,就是這麼霸氣,就是這麼任性。

 

(2.3)傳遞過程中那些可能發生的事

觸摸事件的第一個接收者總是Activity,Activity一般不會去消費觸摸事件,而是直接傳遞給處於該觸摸事件范圍的View樹集合。在View樹中等級位置對應在觸摸事件中的位置,即越外層的View,就位於越頂層,而其child則位於底層。即Activity在最頂層,然後接下來是容器控件,最後的View在最底層。

 

在一般情況下:

事件先從上往下,經過每一個dispatchTouchEvent。到達最後一個View時,調用其onTouchEvent,開始從下往上的傳遞過程,經過每一個onTouchEvent,這是沒任何View想要消費觸摸事件的情況。


可能發生的幾個轉折點:

<1>在從上往下的過程中,如果某個View的onInterceptTouchEvent返回了true,表示攔截事件,事件不會繼續往下傳遞,而是直接調用這個View的onTouchEvent,注意這並不意味著這個View消費了這個事件,只是攔截了這個事件繼續往下傳遞,剝奪了子View的消費權,提前開始從下往上的過程而已,是否由它消費還要看其onTouchEvent的返回值是否為true。(有特殊情況)


<2>在從下往上的過程中,如果某個View的onTouchEvent返回了true,表示自己想要消費這個事件,事件不會繼續往上傳遞,事件傳遞結束。


<3>還是在從下往上的過程中,如果某個View在之前的dispatchTouchEvent方法返回了true,表示在之前這個View表明如果所有子View都不消費這個事件的話,那麼就讓我來消費,事件不會繼續往上傳遞,事件傳遞結束。
(所有子View都不消費這個事件意味著所有子View的dispatchTouchEvent和onTouchEvent都返回了false,不然事件早被消費且傳遞結束了,根本不會再到達自己。)


<4>這個比較少用,某個子View調用了parent的requestDisallowInterceptTouchEvent方法,表示請求parent不要攔截事件,這種情況下parent的onInterceptTouchEvent返回了true也攔截不了事件,即讓onInterceptTouchEvent方法失效,這就是上面3個標記了(有特殊情況)所說的特殊情況。

 

(2.4)記憶功能

記憶功能是指,如果某個View消費了Down事件,那麼接下來的Move和Up等事件還是會從Activity頂層向下傳遞,但是傳遞到這個View時,即使這個View並沒有用onInterceptTouchEvent方法來攔截事件,事件還是會被攔截,直接由該View處理。即如果一個View消費了Down事件,則接下來的Move和Up事件也會交給它消費。

這麼做的原因是:一般情況下單一的觸摸事件並不能形成有效的動作。比如一個拖動動作需要Down事件和連續的Move事件,點擊動作至少需要一個Down事件和Up事件。把單一的觸摸事件分派給不同的View,往往形成不了有意義的動作,所以加入了這個記憶功能來減少事件的傳遞。

 

(3)隨便說點

理解觸摸事件的傳遞一般是為了解決觸摸事件發生沖突的情況,處理觸摸事件沖突時要注意一點:

我們要處理的是由誰來處理觸摸事件,而不是去修改消費這個事件的View應該去怎麼處理。

有點拗口是吧,再說白一點就是我們應該控制誰來處理,而不是控制怎麼去處理,每個View都有自己的處理邏輯,我們不應該去修改它。
舉個栗子:
手指左右拖動不了ViewPager時,我們想得應該是怎麼在手指左右拖動的情況下讓ViewPager能獲得觸摸事件的消費權,而不要管接受到觸摸事件後怎麼讓ViewPager隨著手指滾動,這個功能ViewPager自己已經實現了,你把觸摸事件給它,它就能滾。

 

好了,本篇完結,建議對觸摸事件傳遞機制不熟悉的自己寫個例子打印些Log日志驗證一下,再百度谷歌下一下常見的觸摸沖突及其解決辦法。

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved