編輯:關於Android編程
現在看來其實更像是一篇知識概括,多處可能未講清楚,於是打算重寫事件分發,用一篇文章大致講清楚。
首先,形式上筆者最先思考的是使用源碼,此者能從原理上講解分發機制,比起侃侃而談好得多。但是大量的源碼往往會讓新手產生畏懼難以理解,於是筆者最終還是打算主要使用實例log輸出來讓讀者理解android事件分發。
筆者此次主要提及最常用的幾個函數:
(其間區別看源碼很容易理解,此處直接給上結果)
onClick():這個函數是是View提供給我們的OnClickListener這個接口中的函數,在這裡可以自定義對點擊事件的處理邏輯。會在onTouchEvent()中進行調用。
onTouch():這個函數是View提供給我們的OnTouchListener這個接口中的函數,在這裡面可以自定義對觸摸事件的處理邏輯。
onTouchEvent():這個函數是view內部的觸摸事件的處理方式,其間包括獲取焦點,調用onClick()等等。
dispatchTouchEvent():這個是View的事件分發函數,在ViewGroup中進行重寫。在View中其間會調用onTouchEvent(),在ViewGroup中其間會調用onInterceptTouchEvent()和onTouchEvent()。
onInterceptTouchEvent():這個函數是事件攔截函數,是ViewGroup才有的函數。
此處我們通過一個很簡單的例子進行說明,示例:
示例xml代碼如下:
由外到裡主要是三個LinearLayout,分別為A、B、C。筆者分別在五個關鍵函數中加上了Log,最終點擊一下,輸出的值如下:
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_C
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:28:58.136 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C
01-12 01:28:58.203 2442-2442/com.example.double2.dispatchevent D/XJJ: onClick_C
如上,我們可以看到五個函數的大致執行順序如下:
dispatchTouchEvent() onInterceptTouchEvent() onTouch() onTouchEvent() onClick()好奇的讀者肯定會問,為什麼事件分發執行了兩次呢?
其實很簡單,因為的確有兩個分發的事件,一次是“手指按下”的事件,一次是“手指抬起”的事件。我們可以看到,只有在“手指抬起”的時候,才會觸發onClick()事件。
此處為了便於大家理解,也附上一張事件分發的圖:
然而還有一個值得我們在意的事情,就是onTouch()以及onTouchEvent()只有在C中執行,而在B和A的就不執行了。
此處,我們就必須再講一點了。
dispatchTouchEvent()、onInterceptTouchEvent() 、onTouch()、onTouchEvent()這四個函數,返回值為false的時候,事件會繼續向下分發,一旦返回值為true,事件就不再向下分發。
而onClick()沒有返回值
根據這點我們可以知道,一定是C的onTouchEvent()中返回了true,我們將其更改後再看一下效果。
原來的代碼為:
@Override public boolean onTouchEvent(MotionEvent event) { Log.d("XJJ","onTouchEvent_C"); return super.onTouchEvent(event); }
更改後:
@Override public boolean onTouchEvent(MotionEvent event) { Log.d("XJJ","onTouchEvent_C"); return false; }
效果:
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_C
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_B
01-12 01:24:06.250 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_B
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_B
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_B
01-12 01:24:06.360 2442-2442/com.example.double2.dispatchevent D/XJJ: onClick_B
這樣操作之後,我們可以發現,“手指按下”時,onTouch()以及onTouchEvent()事件就可以傳遞到B了。但是同時,我們也可以發現,當“手指抬起”時,C的onTouch()以及onTouchEvent()事件就不會執行了。
當然,如果需要onTouch()以及onTouchEvent()事件傳遞到A,那麼只需要將B的onTouchEvent()也返回false即可。(此處就不重復演示了)
那麼如果onTouchEvent()返回值設置為true了之後,是不是onClick()事件是不是就不會執行了呢?效果如下:
01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A 01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A 01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B 01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B 01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C 01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_C 01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C 01-12 01:39:21.560 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C 01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A 01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A 01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B 01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B 01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C 01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C 01-12 01:39:21.617 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_C
onClick()的確是不會執行了,如此我們也嘗試一下onTouch()返回值設置為true,效果如下:
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_C
01-12 01:40:41.101 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_C
01-12 01:40:41.173 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_C
如此,我們可知,當onTouch()返回值設置為true的時候,onTouchEvent()的確是不會執行了。
到這裡,我們其實只剩下對onInterceptTouchEvent() 的分析了,為何沒有dispatchTouchEvent()了呢?
因為dispatchTouchEvent()是事件分發的函數,對View而言,我們阻止它內部的事件分發是沒有什麼意義的,而我們要控制ViewGroup的事件分發則是通過onInterceptTouchEvent() 來執行的。
如此我們便假設一個應用場景,A包括B,B包括C,B為橫向滑動,C為豎向滑動,當橫向滑動的加速度大於豎向滑動的加速度的時候,我們僅僅讓B響應事件,而不把事件傳遞給C。
我們可以通過onInterceptTouchEvent() 來實現,僅僅只需將B的onInterceptTouchEvent()返回值設置為true即可,效果如下:
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_B
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_B
01-12 01:50:18.513 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_B
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_A
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: onInterceptTouchEvent_A
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: dispatchTouchEvent_B
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouch_B
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: onTouchEvent_B
01-12 01:50:18.621 2442-2442/com.example.double2.dispatchevent D/XJJ: onClick_B
前言 我K,今天居然是情人節,對於資深的單身狗來說,簡直是個噩耗,今天注定是各種秀恩愛,心塞中。。。。 話題到此結束,管他什麼情人節,今天給大家帶來的
一、批量打包1、集成了友盟統計,並在AndroidManifest.xml中添加了如下代碼<meta-dataandroid:name=UMENG_CHANNELa
spinner組件有點類型於HTML中的下拉框<Select></select>的樣子,讓用戶每次從下拉框中選取一個,本文為大家分享了Androi
這幾天做項目,有些地方的圖片需要用到圓形圖片,所以百度了一下,在github上找到一個開源項目,處理很簡單,效果如下: 使用起來特別簡單,一共三步,具體如下:&