Android開發藝術探索筆記——View(二)

Android開發藝術探索筆記——View(二)

View的事件分發機制

學習資料:
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.MotionEventhtml

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

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

屬性有:android

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

View的事件分發,就是對MotionEvent事件的分發過程。程序員

事件分發的三個重要方法:ide

//用於分發事件(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)

三個方法的關係可用以下僞代碼描述:學習

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

viewTouchEvent

View的onTouchListener的優先級比onTouchEvent方法的高。ui

運動事件的傳遞順序:spa

Activity-->Window-->View

下面是將ViewdispatchTouchEvent()方法設置斷點後,點擊ImageView的調試過程:調試

viewTouchEvent

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

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

View的事件分發機制相似於互聯網公司的工做流程:

新任務:
 CEO-->產品經理-->CTO-->開發小組組長-->程序員
 
 由上至下一級一級分發任務(dispatchTouchEvent),若是是本身的任務(onInterceptTouchEvent)
 ,則攔截本身處理(onTouchEvent),反之,則交由下級分發(child.dispatchTouchEvent)。
 
 若是事情搞不定,就一級一級向上拋(parent.onTouchEvent):
 程序員-->開發組長-->CTO-->產品經理-->CEO

事件傳遞機制的一些結論:

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

事件分發源碼解析

Activity對事件的分發過程

  • 1.點擊事件首先傳遞給Activity,而後由ActivitydispatchTouchEvent()方法進行事件的分發。Activity會將事件交由window進行分發。
//Activity源碼
 ...
 /*
  * Activity的dispatchTouchEvent方法
  */
 public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction();
        }
        //Activity交由window進行事件分發
        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類的惟一實現類。

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

能夠看到PhoneWindow類在實現抽象方法superDispatchTouchEvent時,直接將事件交由DecorView處理。

相關文章
相關標籤/搜索