[Android面試題-10] TouchEvent的分發和截獲方式

android系統中的每個ViewGroup的子類都具有下面三個和TouchEvent處理密切相關的方法:

1)public boolean dispatchTouchEvent(MotionEvent ev)          這個方法用來分發TouchEvent

2)public boolean onInterceptTouchEvent(MotionEvent ev)         這個方法用來攔截TouchEvent

3)public boolean onTouchEvent(MotionEvent ev)                 這個方法用來處理TouchEvent

注意:不是所有的View的子類,很多教程都說的是所有的View的子類,只有可以向裏面添加View的控件才需要分發,比如TextView它本身就是最小的view了,所以不用再向它的子視圖分發了,它也沒有子視圖了,所以它沒有dispatch和Intercept,只有touchEvent。


onInterceptTouchEvent(MotionEvent ev)方法是GroupView控件中特有的一個方法,我們可以實現這個方法來截獲所有的窗口點擊事件來根據事件的不同來對子控件或自身分發事件觸發。覆蓋這個方法時需要小心注意,因爲它和View.onTouchEvent(MotionEvent)有着複雜的關係,我們使用是需要和View.onTouchEvent(MotionEvent)一同實現來達到正確的結果,事件觸發順序如下:

  1.你首先會在該方法中得到一個down事件。

  2.這個down事件會被得到處理,要麼在這個GroupView中子控件的onTouchEvent()方法中,要麼在GroupView自身的onTouchEvent()方法中。當我們在onTouchEvent()方法返回值中返回true的話,將會繼續看到後續的觸發事件(move、up等),要注意的是當我們在GroupView的onTouchEvent()事件返回值中返回false的話,該方法將不再捕獲後續的(move up)事件。

  3.如果在該方法返回值中返回false,down事件將根據控件樹結構從根節點向目標子控件的onTouchEvent()方法分發。

  4.如果在該方法返回值中返回true,那麼你的子控件將獲取不到任何點擊事件。

 

  爲證明上面所說的順序特點,下面通過測試代碼來觀察觀察:

  

複製代碼
 1 public class MainActivity extends Activity {
 2     Group1 group1;
 3     Group2 group2;
 4     MyTextView myTv;
 5 
 6     /** Called when the activity is first created. */
 7     @Override
 8     public void onCreate(Bundle savedInstanceState) {
 9         super.onCreate(savedInstanceState);
10         
11         
12         //--group1
13         //----|
14         //-------group2
15         //---------|
16         //------------myTv
17         
18         group1 = new Group1(this);
19         group2 = new Group2(this);
20         myTv = new MyTextView(this);
21         group2.addView(myTv, new LayoutParams(LayoutParams.FILL_PARENT,
22                 LayoutParams.FILL_PARENT));
23         group1.addView(group2, new LayoutParams(LayoutParams.FILL_PARENT,
24                 LayoutParams.FILL_PARENT));
25         setContentView(group1);
26     }
27 }
複製代碼

  分別重寫Group1和Group2的onInterceptTouchEvent和onTouchEvent方法,重寫MyTextView的onTouchEvent方法,最終得到的控件層次結構如下:  

   

  1.在默認返回值情況下logcat輸出如下:  

     

  測試後可知默認情況下和所有方法返回值爲false的結果一致,down事件的捕獲順序onInterceptTouchEvent先於onTouchEvent,由於onTouchEvent返回值爲false,down事件沒被消化,後續的move和up事件沒有出現,同時逆序返回到父控件的onTouchEvent方法來捕獲,如下圖所示:  

   

 

  2.所有onTouchEvent返回值爲true情況下logcat輸出如下:

   

  輸出結果可以看出子控件MyTextView消化了down事件,後續的move和up事件正常捕獲,由於down事件被消化,上層的onTouchEvent方法不執行,如下圖所示:(三箭頭分別指down、move、up事件)

   

  既然如此,如果MyTextView中onTouchEvent方法返回爲false,而group1和group2的onTouchEvent方法返回true的結果自然也就如下圖的順序了:  

  

  測試輸出結果證明了這一猜測順序,  

     

 

  3.當某個GroupView中的onInterceptTouchEvent方法返回值爲true情況下logcat輸出如下(如group2):

    

  如果在該方法返回值中返回true,那麼子控件將獲取不到任何點擊事件,轉而向自身的onTouchEvent方法轉發,如下圖所示:

  

  如果onTouchEvent方法返回值都爲true,那麼根據規律結果就如下圖順序觸發:  

    

  最後logcat的結果證實了這一猜測,  

     

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