2、Touch 案例介紹 android
一樣在開始進行案例分析以前,我須要說明測試案例的結構,由於全部的測試都是針對這一個案例來進行的,測試中只是經過修改每一個控件中與 Touch 事件相關的三個方法的返回值來體現不一樣的狀況。先來看張圖: app
上面的圖爲測試案例的佈局文件 UI 顯示效果,佈局文件代碼以下: 工具
<?xml version="1.0" encoding="utf-8"?> <cn.sunzn.tevent.TouchEventFather xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#468AD7" android:gravity="center" android:orientation="vertical" > <cn.sunzn.tevent.TouchEventChilds android:id="@+id/childs" android:layout_width="200dp" android:layout_height="200dp" android:layout_gravity="center" android:background="#E1110D" android:text="@string/hello" /> </cn.sunzn.tevent.TouchEventFather>
藍色背景爲一個自定義控件 TouchEventFather,該控件爲外層 View,繼承自 LinearLayout,實現代碼以下: 佈局
package cn.sunzn.tevent; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.LinearLayout; public class TouchEventFather extends LinearLayout { public TouchEventFather(Context context) { super(context); } public TouchEventFather(Context context, AttributeSet attrs) { super(context, attrs); } public boolean dispatchTouchEvent(MotionEvent ev) { Log.e("sunzn", "TouchEventFather | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction())); return super.dispatchTouchEvent(ev); } public boolean onInterceptTouchEvent(MotionEvent ev) { Log.i("sunzn", "TouchEventFather | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction())); return super.onInterceptTouchEvent(ev); } public boolean onTouchEvent(MotionEvent ev) { Log.d("sunzn", "TouchEventFather | onTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction())); return super.onTouchEvent(ev); } }
紅色背景爲一個自定義控件 TouchEventChilds,該控件爲內層 View,爲 TouchEventFather 的子 View,一樣繼承自 LinearLayout,實現代碼以下: 測試
package cn.sunzn.tevent; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.LinearLayout; public class TouchEventChilds extends LinearLayout { public TouchEventChilds(Context context) { super(context); } public TouchEventChilds(Context context, AttributeSet attrs) { super(context, attrs); } public boolean dispatchTouchEvent(MotionEvent ev) { Log.e("sunzn", "TouchEventChilds | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction())); return super.dispatchTouchEvent(ev); } public boolean onInterceptTouchEvent(MotionEvent ev) { Log.i("sunzn", "TouchEventChilds | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction())); return super.onInterceptTouchEvent(ev); } public boolean onTouchEvent(MotionEvent ev) { Log.d("sunzn", "TouchEventChilds | onTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction())); return super.onTouchEvent(ev); } }
接着實現 Activity 的代碼,由於控件全部的事件都是經過 Activity 的 dispatchTouchEvent 進行分發的;除此以外還須要重寫 Activity 的 onTouchEvent 方法,這是由於若是一個控件直接從 Activity 獲取到事件,這個事件會首先被傳遞到控件的 dispatchTouchEvent 方法,若是這個方法 return false,事件會以冒泡方式返回給 Activity 的 onTouchEvent 進行消費。實現代碼以下:
spa
package cn.sunzn.tevent; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; public class TouchEventActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public boolean dispatchTouchEvent(MotionEvent ev) { Log.w("sunzn", "TouchEventActivity | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction())); return super.dispatchTouchEvent(ev); } public boolean onTouchEvent(MotionEvent event) { Log.w("sunzn", "TouchEventActivity | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction())); return super.onTouchEvent(event); } }
最後再附上 TouchEventUtil 的代碼,TouchEventUtil 中並無作多少事情,只是將以上 2 個自定義控件中各個方法的 MotionEvent 集中到一個工具類中並將其對應的動做以 String 形式返回,這樣處理更便於實時觀察控件的事件。代碼以下: code
package cn.sunzn.tevent; import android.view.MotionEvent; public class TouchEventUtil { public static String getTouchAction(int actionId) { String actionName = "Unknow:id=" + actionId; switch (actionId) { case MotionEvent.ACTION_DOWN: actionName = "ACTION_DOWN"; break; case MotionEvent.ACTION_MOVE: actionName = "ACTION_MOVE"; break; case MotionEvent.ACTION_UP: actionName = "ACTION_UP"; break; case MotionEvent.ACTION_CANCEL: actionName = "ACTION_CANCEL"; break; case MotionEvent.ACTION_OUTSIDE: actionName = "ACTION_OUTSIDE"; break; } return actionName; } }
3、Touch 案例分析 xml
Case 1
繼承
攔截條件 | |||||
控件名稱 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||
TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||
TouchEventFather | false | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||
TouchEventChilds | super.dispatchTouchEvent(ev) | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||
運行結果 | |||||
Level | Time | PID | Application | Tag | Text |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN |
E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_DOWN |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_UP |
結果分析 | |||||
代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的dispatchTouchEvent,而該控件的 dispatchTouchEvent 返回 false,表示對獲取到的事件中止向下傳遞,同時也不對該事件進行消費。因爲 TouchEventFather 獲取的事件直接來自 TouchEventActivity ,則會將事件返回給 TouchEventActivity 的 onTouchEvent 進行消費,最後直接由 TouchEventActivity 來響應手指移動和擡起事件。 |
Case 2 事件
攔截條件 | |||||
控件名稱 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||
TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||
TouchEventFather | true | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||
TouchEventChilds | super.dispatchTouchEvent(ev) | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||
運行結果 | |||||
Level | Time | PID | Application | Tag | Text |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN |
E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP |
E | 05-10 03:41:19.743 | 414 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_UP |
結果分析 | |||||
代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent,而該控件的 dispatchTouchEvent 返回 true,表示分發事件到 TouchEventFather 控件並由該控件的 dispatchTouchEvent 進行消費;TouchEventActivity 不斷的分發事件到 TouchEventFather 控件的dispatchTouchEvent,而 TouchEventFather 控件的 dispatchTouchEvent 也不斷的將獲取到的事件進行消費。 |
Case 3
攔截條件 | |||||
控件名稱 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||
TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||
TouchEventFather | super.dispatchTouchEvent(ev) | true | super.onTouchEvent(ev) | ||
TouchEventChilds | super.dispatchTouchEvent(ev) | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||
運行結果 | |||||
Level | Time | PID | Application | Tag | Text |
W | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN |
E | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN |
I | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_DOWN |
D | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventFather | onTouchEvent --> ACTION_DOWN |
W | 05-10 05:34:46.333 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_DOWN |
W | 05-10 05:34:46.343 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 05:34:46.343 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE |
W | 05-10 05:34:46.423 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 05:34:46.423 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE |
W | 05-10 05:34:46.433 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 05:34:46.433 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE |
W | 05-10 05:34:46.442 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP |
W | 05-10 05:34:46.442 | 481 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_UP |
結果分析 | |||||
代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent,而該控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示對事件進行分發並向下傳遞給 TouchEventFather 控件的 onInterceptTouchEvent 方法,該方法返回 true 表示對所獲取到的事件進行攔截並將事件傳遞給 TouchEventFather 控件的 onTouchEvent 進行處理,TouchEventFather 控件的 onTouchEvent 返回 super.onTouchEvent(ev) 表示對事件沒有作任何處理直接將事件返回給上級控件,因爲 TouchEventFather 獲取的事件直接來自 TouchEventActivity,因此 TouchEventFather 控件的 onTouchEvent 會將事件以冒泡方式直接返回給 TouchEventActivity 的 onTouchEvent 進行消費,後續的事件則會跳過 TouchEventFather 直接由 TouchEventActivity 的 onTouchEvent 消費來自 TouchEventActivity 自身分發的事件。 |
Case 4
攔截條件 | |||||
控件名稱 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||
TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||
TouchEventFather | super.dispatchTouchEvent(ev) | false | super.onTouchEvent(ev) | ||
TouchEventChilds | super.dispatchTouchEvent(ev) | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||
運行結果 | |||||
Level | Time | PID | Application | Tag | Text |
W | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN |
E | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN |
I | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_DOWN |
E | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventChilds | dispatchTouchEvent --> ACTION_DOWN |
I | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventChilds | onInterceptTouchEvent --> ACTION_DOWN |
D | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventChilds | onTouchEvent --> ACTION_DOWN |
D | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventFather | onTouchEvent --> ACTION_DOWN |
W | 05-10 06:31:47.565 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_DOWN |
W | 05-10 06:31:47.652 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 06:31:47.652 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE |
W | 05-10 06:31:47.732 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 06:31:47.732 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE |
W | 05-10 06:31:47.812 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 06:31:47.812 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_MOVE |
W | 05-10 06:31:47.892 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP |
W | 05-10 06:31:47.892 | 512 | cn.sunzn.tevent | sunzn | TouchEventActivity | onTouchEvent --> ACTION_UP |
結果分析 | |||||
代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent,而該控件的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示對事件進行分發並向下傳遞給 TouchEventFather 控件的 onInterceptTouchEvent 方法,該方法返回 false 表示事件會被放行並傳遞到子控件 TouchEventChilds 的 dispatchTouchEvent 方法,一樣 TouchEventChilds 的 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev),表示對事件進行分發並向下傳遞給 TouchEventChilds 控件的 onInterceptTouchEvent 方法,TouchEventChilds 的 onInterceptTouchEvent 方法返回 super.onInterceptTouchEvent(ev) 默認會將事件傳遞給 TouchEventChilds 的 onTouchEvent 進行處理,TouchEventChilds 的 onTouchEvent 返回 super.onTouchEvent(ev) 表示對事件沒有作任何處理直接將事件返回給上級控件,因爲 TouchEventChilds 獲取的事件直接來自 TouchEventFather,因此 TouchEventChilds 控件的 onTouchEvent 會將事件以冒泡方式直接返回給 TouchEventFather 的 onTouchEvent 進行消費,而 TouchEventFather 的 onTouchEvent 也返回了 super.onTouchEvent(ev),一樣 TouchEventFather 的 onTouchEvent 也會將事件返回給上級控件,而 TouchEventFather 獲取的事件直接來自 TouchEventActivity,因此 TouchEventFather 控件的 onTouchEvent 會將事件以冒泡方式直接返回給 TouchEventActivity 的 onTouchEvent 進行消費,後續的事件則會跳過 TouchEventFather 和 TouchEventChilds 直接由 TouchEventActivity 的 onTouchEvent 消費來自 TouchEventActivity 自身分發的事件。 |
Case 5
攔截條件 | |||||
控件名稱 | dispatchTouchEvent 返回值 | onInterceptTouchEvent 返回值 | onTouchEvent 返回值 | ||
TouchEventActivity | super.dispatchTouchEvent(ev) | --- | super.onTouchEvent(ev) | ||
TouchEventFather | super.dispatchTouchEvent(ev) | false | super.onTouchEvent(ev) | ||
TouchEventChilds | true | super.onInterceptTouchEvent(ev) | super.onTouchEvent(ev) | ||
運行結果 | |||||
Level | Time | PID | Application | Tag | Text |
W | 05-10 08:11:18.403 | 574 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_DOWN |
E | 05-10 08:11:18.403 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_DOWN |
I | 05-10 08:11:18.403 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_DOWN |
E | 05-10 08:11:18.403 | 574 | cn.sunzn.tevent | sunzn | TouchEventChilds | dispatchTouchEvent --> ACTION_DOWN |
W | 05-10 08:11:19.652 | 574 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_MOVE |
E | 05-10 08:11:19.652 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_MOVE |
I | 05-10 08:11:19.652 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_MOVE |
E | 05-10 08:11:19.652 | 574 | cn.sunzn.tevent | sunzn | TouchEventChilds | dispatchTouchEvent --> ACTION_MOVE |
W | 05-10 08:11:19.872 | 574 | cn.sunzn.tevent | sunzn | TouchEventActivity | dispatchTouchEvent --> ACTION_UP |
E | 05-10 08:11:19.872 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | dispatchTouchEvent --> ACTION_UP |
I | 05-10 08:11:19.872 | 574 | cn.sunzn.tevent | sunzn | TouchEventFather | onInterceptTouchEvent --> ACTION_UP |
E | 05-10 08:11:19.872 | 574 | cn.sunzn.tevent | sunzn | TouchEventChilds | dispatchTouchEvent --> ACTION_UP |
結果分析 | |||||
代碼運行後,事件首先由 TouchEventActivity 的 dispatchTouchEvent 方法分發給 TouchEventFather 控件的 dispatchTouchEvent,該控件的 dispatchTouchEvent 返回super.dispatchTouchEvent(ev),事件會分發到 TouchEventFather 的 onInterceptTouchEvent,onInterceptTouchEvent 返回 false 表示放行當先事件;事件會被傳遞到子控件 TouchEventChilds 的 dispatchTouchEvent 方法,dispatchTouchEvent 返回 true 表示事件被分發到 TouchEventChilds 控件並由該控件的 dispatchTouchEvent 方法消費。後續的事件也會不斷的重複上面的邏輯最終被 TouchEventChilds 的 dispatchTouchEvent 消費。 |