Android Touch 事件分發感悟

本編意在指引入門,非技術性分析文章,以生活中的實例幫你更好的理解 touch 事件的傳遞。bash

回憶剛接觸 touch 事件傳遞時,文章大可能是源碼分析,對於有基礎的人來講,上手很容易,但對於我這種新手來講,心中有萬馬奔騰。。。源碼分析

其實事件的分發能夠轉換成咱們生活中的場景:

炎炎夏日,你和你爸爸都很熱,如今在你爸爸手裏有一根雪糕,那麼這根雪糕怎麼分、誰吃就能夠演變成 Android touch 的事件分發。ui

咱們先說說結果,雪糕無非就三種,你吃、你爸爸吃、都不吃this

先說說你爸爸吃的狀況:

  • 你爸爸不問你要不要,直接留下給本身,而後直接吃了。
  • 你爸爸問你要不要,你說不要,而後你爸爸吃了。

再說說你吃的狀況:

  • 你爸爸問你要不要,你說要,你爸爸就給你吃了。
  • 你爸爸不問你要不要,可是你告訴你爸爸說你想吃,你爸爸雖然想吃,但仍是給你了。

最後都不吃的狀況:

  • 你爸爸不吃,問你吃不吃,你也不吃,這時候就沒人吃了。

上面這個場景應該很容易理解,那麼換到 Android 的 touch 事件分發中,

  • 雪糕 = touch 事件,被封裝成 MotionEvent 對象中。
  • 你爸爸 = ViewGroup,父 View,有 dispatchTouchEvent(拿到雪糕)、onInterceptTouchEvent(不問你,留下給本身)、onTouch(吃雪糕)三個方法。
  • 你 = View,子 View,有 dispatchTouchEvent(拿到雪糕)、onTouch(吃雪糕)兩個方法。

經過這個場景,你們將方法帶入,是否是就很容易理解了呢?spa

疑問一:爲何子 View 沒有 onInterceptTouchEvent 這個呢?

由於你已是最後一個了,不用問誰了,直接決定吃不吃就能夠了。.net

疑問二:你吃裏面的第二種狀況,爲何你爸爸都決定本身吃了,但爲何只要你說你想吃,他就會給你呢?

其實你爸爸可否吃到雪糕的決定權仍是在你的手裏,code

僞代碼:對象

if( 孩子是否想吃 || !爸爸是否留下){
    給孩子吃
}else{
    爸爸吃
}
複製代碼

默認孩子不想吃(false),爸爸不留下(false),blog

if( false || !false){
    給孩子吃
}else{
    爸爸吃
}
複製代碼

正常的狀況下都會給孩子吃, 當爸爸留下(true)時,事件

if( false || !true){
    給孩子吃
}else{
    爸爸吃
}
複製代碼

就走到了 else 中,也就是爸爸吃。

在 Android 中咱們能夠經過 requestDisallowInterceptTouchEvent(孩子是否想吃)這個方法改變孩子是否想吃的值,當孩子調用requestDisallowInterceptTouchEvent方法返回 true 時,不管爸爸是否想吃,都會走到孩子想吃中,也就是最終結果是你吃。

if( true || !爸爸是否留下){
    給孩子吃
}else{
    爸爸吃
}
複製代碼

咱們的終極僞代碼:

// 標記子 view 請求是否不攔截(孩子是否想吃,默認不想)
boolean disallowIntercept = false;
// 調用 dispatchTouchEvent(爸爸拿來了一根雪糕)
public boolean dispatchTouchEvent(MotionEvent ev) {
    // 標記事件是否被消費掉(雪糕是否被吃)
    boolean consume = false; 
    // 判斷是否攔截事件(雪糕給不給孩子)
    if ( disallowIntercept || !onInterceptTouchEvent(ev)) {
      // 若攔截,則將該事件交給當前View進行處理
      // 即調用onTouchEvent 方法去處理點擊事件(爸爸吃雪糕)
        consume = onTouchEvent (ev) ;
    } else {
      // 若不攔截,則將該事件傳遞到下層,即下層元素的dispatchTouchEvent就會被調用,直到點擊事件被最終處理爲止(孩子吃或者不吃)
      consume = child.dispatchTouchEvent (ev) ;
    }
    // 最終返回通知 該事件是否被消費(吃或不吃)
    return consume;
}
// 子 view 能夠經過調用此方法 改變 disallowIntercept 的值
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept){
    this.disallowIntercept = disallowIntercept;
}
複製代碼

這裏有幾篇很是好的講解:

相關文章
相關標籤/搜索