Android開發(fā)藝術(shù)探索筆記——View(二)

Android開發(fā)藝術(shù)探索筆記——View(二)

View的事件分發(fā)機制

學習資料:
1.Understanding Android Input Touch Events System Framework
2.Managing Touch Events in a ViewGroup
3.Android事件傳遞機制
4.Input Events
5.Mastering the Android Touch System
6.MotionEvent

MotionEvent(運動事件)的傳遞規(guī)則

用戶每次觸摸屏幕都被包裝成了MotionEvent(運動事件)對象。

屬性有:

  • 動作碼(action code),如ACTION_DOWN,ACTION_UP等等,用于描述用戶當前的動作。
  • 觸摸的橫縱坐標。
  • 其它信息,如壓力,大小以及方向等等。

View的事件分發(fā),就是對MotionEvent事件的分發(fā)過程。

事件分發(fā)的三個重要方法:

//用于分發(fā)事件(dispatch touch event),要么將事件向下傳遞到目標View,要么交由自己處理。
//返回true表示自己處理
public boolean dispatchTouchEvent (MotionEvent event)


//用于攔截事件(intercept touch event),ViewGroup中有,View中沒有這個方法。
public boolean onInterceptTouchEvent (MotionEvent event)


//用于處理事件
public boolean onTouchEvent (MotionEvent event)

三個方法的關(guān)系可用如下偽代碼描述:

public boolean dispatchTouchEvent(MotionEvent ev){
   boolean consume = false;
   if(onInterceptTouchEvent(ev)){
     consume = true;
   }else{
     consume = child.dispatchTouchEvent(ev);
   }
   return consume;
}
viewTouchEvent

View的onTouchListener的優(yōu)先級比onTouchEvent方法的高。

運動事件的傳遞順序:

Activity-->Window-->View

下面是將ViewdispatchTouchEvent()方法設(shè)置斷點后,點擊ImageView的調(diào)試過程:

viewTouchEvent

能清楚地看到事件的傳遞過程和順序。

若View的onTouchEvent()方法返回false,則會調(diào)用它的父View的onTouchEvent()方法,依此類推,若調(diào)用順序上的所有View都不處理這個事件,則這個事件會最終傳遞給Activity的onTouchEvent()方法。

View的事件分發(fā)機制類似于互聯(lián)網(wǎng)公司的工作流程:

 新任務(wù):
 CEO-->產(chǎn)品經(jīng)理-->CTO-->開發(fā)小組組長-->程序員
 
 由上至下一級一級分發(fā)任務(wù)(dispatchTouchEvent),如果是自己的任務(wù)(onInterceptTouchEvent)
 ,則攔截自己處理(onTouchEvent),反之,則交由下級分發(fā)(child.dispatchTouchEvent)。
 
 如果事情搞不定,就一級一級向上拋(parent.onTouchEvent):
 程序員-->開發(fā)組長-->CTO-->產(chǎn)品經(jīng)理-->CEO
 

事件傳遞機制的一些結(jié)論:

  • 1.事件序列:從手指接觸屏幕到手指離開屏幕的過程,ACTION_DOWN-->ACTION_MOVE-->...-->ACTION_MOVE-->ACTION_UP
  • 2.一個事件序列只能被一個View攔截且消費。
  • 3.ViewGroup默認不攔截事件。源碼中ViewGroup的onInterceptTouchEvent()方法默認返回false
  • 4.View沒有onInterceptTouchEvent()方法
  • 5.事件傳遞是由外向內(nèi)(由上至下)的。事件先傳遞給父元素,然后再由父元素分發(fā)給子元素。通過 requestDisallowInterceptTouchEvent()方法可以在子元素中干預(yù)父元素的事件分發(fā)過程。

事件分發(fā)源碼解析

Activity對事件的分發(fā)過程

  • 1.點擊事件首先傳遞給Activity,然后由ActivitydispatchTouchEvent()方法進行事件的分發(fā)。Activity會將事件交由window進行分發(fā)。
//Activity源碼
 ...
 /*
  * Activity的dispatchTouchEvent方法
  */
 public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        //Activity交由window進行事件分發(fā)
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }
  • 2.Window將事件傳遞給DecorView(即ContentView的父View,可通過Activity.getWindow().getDecorView()方法獲取)。而Window類是抽象類,superDispatchTouchEvent()方法是抽象方法。
//Window類是抽象類
public abstract class Window {
...
//window的superDispatchTouchEvent方法是抽象方法
public abstract boolean superDispatchTouchEvent(MotionEvent event);
...
}

而PhoneWindow類是Window類的唯一實現(xiàn)類。


public class PhoneWindow extends Window implements MenuBuilder.Callback {
...
  @Override
    public boolean superDispatchTouchEvent(MotionEvent event)       { 
    //PhoneWindow直接將事件交友DecorView處理
    return mDecor.superDispatchTouchEvent(event);
    }
 ...
 }

可以看到PhoneWindow類在實現(xiàn)抽象方法superDispatchTouchEvent時,直接將事件交由DecorView處理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容