Android中事件分發機制

     Android(觸摸屏)中應用程序與用戶交互用的就是touch事件來完成的,一個界面上的控件會有很多,那麼
 一個touch事件是如何傳遞的呢?
  一、簡介
	Android中的touch事件都是以down(按下)事件開始,up(擡起)事件結束的
        事件類型有:ACTION_DOWN(按下)、ACTION_UP(擡起)、ACTION_MOVE(移動)
	           ACTION_POINT_DOWN(多個手指按下)、ACTION_POINT_UP(多個手指擡起)
  二、事件分發
      Android中的View分爲兩個,一類是ViewGroup(含有子類View);一類是View(沒有子類View),兩類的
    事件分發機制有所不同
      1.View
	有兩個控件TextView和Button,分別點擊一次,並且打印響應的信息(onTouch默認返回爲false)
	單擊一次有兩個事件響應:down和up分別執行一次,首先down事件執行如下
	
button.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                System.out.println("button");
                return false;
            }
        });

        textView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                System.out.println("textView");
                return false;
            }
        });

	    分別點擊一次後打印出來的效果如下
	
	爲什麼點擊兩個控件最後打印出信息的數量是不同的呢,那我們首先要從TextView和Button的不同
      入手,TextView默認是不可點擊的,Button是可以點擊的,然後帶着這兩點不同,看看系統的源碼有
      一下重大的發現呢!!
	①button和textView都是View的子類,通過setOnTouchListener把OnTouchListener對象傳到View
	  
public boolean dispatchTouchEvent(MotionEvent event) {
	        ....
			//mOnTouchListener不爲空,並且當前控件可用,onTouch方法對應得返回值
	        if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
	                mOnTouchListener.onTouch(this, event)) {
	            return true;
	        }
			//如果if對於邏輯不成立,調用onTouchEvent
			//onTouch先於onTouchEvent,並且覺得當前onTouchEvent是否調用
	        return onTouchEvent(event);
	    }

	②兩個子View的onTouch返回值都爲false,那麼會執行本View的onTouchEvent(Event);
	③View的onTouchEvent()方法執行如下
	
public boolean onTouchEvent(MotionEvent event) {
	       	....
			//判斷當前控件是否有點擊事件,如果有則執行if中邏輯,如果沒有則不執行返回false
	        if (((viewFlags & CLICKABLE) == CLICKABLE ||
	                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
	            switch (event.getAction()) {
					//點擊事件觸發點
	                case MotionEvent.ACTION_UP:
	                   ...
                       performClick();
                       ...
	            }
				//此處返回true則說明onTouchEvent,說明dispatchTouchEvent返回true,則響應所有事件
	            return true;
	        }
			//此處返回false,等同於onTouchEvent,dispatchTouchEvent返回false,不響應所有事件
	        return false;
	    }

	  TextView不可點擊,那麼直接返回false,表示事件沒有被消耗,那麼down事件沒有被消耗,up事
	  件也不會繼續執行,所以textView只輸出了一次結果
	  Button可以默認可被點擊,那麼會繼續執行if語句中的內容,繼而回響應up事件,所以會輸出兩次
	  結果
 	④如果給TextView設置一個點擊事件的監聽,那麼也會輸出兩次結果,這是爲什麼呢?因爲在監聽
	  事件的源碼中有如下的一段代碼
		
public void setOnClickListener(OnClickListener l) {
			//如果當前控件沒有點擊事件,設置一個點擊事件
	        if (!isClickable()) {
	            setClickable(true);
	        }
	        mOnClickListener = l;
	    }

	  就算TextView不可點擊,系統也會給它設置爲可點擊的,那麼他就可以和Button一樣了
     2.ViewGroup
	ViewGroup中事件分發和View有點不同,因爲ViewGroup有子View,這就會有事件的分發或者攔截了
	每個ViewGroup都有以下三個方法
		dispatchTouchEvent();	負責事件的分發
		onInterceptTouchEvent();負責事件的攔截
		onTouchEvent();		負責響應事件
	ViewGroup佈局如下圖
		
	 首先是down事件的分發
	  ViewGroup①在分發事件之前會調用自己的onInterceptTouchEvent()方法判斷是否攔截,如果返
	回false(不攔截),那麼分發給ViewGroup②的dispatchTouchEvent事件,它在分發之前也會判斷自己
	是否要攔截,如果不攔截,那麼傳遞給子View③,這時③不能再向下分發啦,需要判斷onTouchEvent
	是否消耗該down事件,如果返回爲True(不消耗),繼續向上返回給②的onTouchEvent,依次類推
	在分發的過程中如果ViewGroup把事件攔截或者消耗掉了down事件,那麼後續的move,up等事件會直
	接傳遞給它不會再走判斷的流程
  三、小結
	以上是對Android事件的簡單理解,其實我們在用手機的時候主要就是在touch手機屏幕,對touch的
     原理搞明白了,那麼對於view是否該獲得事件,以及viewGroup是否該攔截事件都會非常清楚




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章