標籤:android 事件分發
當你作為一名應屆生去面試的時候,面試官可能就是簡單的問你Android的四大組件,各種布局等基礎知識,但你作為一名有工作經驗的應聘者就不會那麼簡單了,今天就來討論很多面試官喜歡問的Android的事件分發.
Android為什麼要有事件分發呢?因為它是按照層排列,他如何知道你點擊的哪一層呢,就需要用到事件分發了.
說到事件分發可能就會想起那三個威武的方法:事件分發(dispatchTouchEvent(MotionEvent ev))、事件攔截(onInterceptTouchEvent(MotionEvent ev))、事件響應(onTouchEvent(MotionEvent ev)),其中ViewGroup響應這三個方法,View要看它是否有子View,沒有子View時不響應事件攔截,Activity不響應事件攔截.
這裡先給出一張事件分發的流程圖
當然不是所有情況下都這麼走,當你的View和ViewGroup都是系統預設的情況下,是根據的流程走,只要View或者ViewGroup中的任何一個對事件感興趣,流程就不一定是什麼樣子了,這個需要具體問題具體分析
下面通過一個demo分析一下具體問題,demo只貼一下代碼,不提供代碼,希望自己動動手,寫寫,看看到底是什麼樣子的
我寫的demo一個有三部分,Activity,View,ViewGroup三部分,重寫了一下那三個威武的函數,當然像activity這樣的就不用寫事件攔截,學著靈活運用
1,activity代碼
package com.thea.guo;import android.os.Bundle;import android.app.Activity;import android.util.Log;import android.view.Menu;import android.view.MotionEvent;import android.view.View;import android.widget.Button;public class MainActivity extends Activity {Button button;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:Log.d("com.thea.guo", "MainActivity.dispatchTouchEvent is down");break;case MotionEvent.ACTION_MOVE:Log.d("com.thea.guo", "MainActivity.dispatchTouchEvent is moving");break;case MotionEvent.ACTION_UP:Log.d("com.thea.guo", "MainActivity.dispatchTouchEvent is up");break;}return super.dispatchTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:Log.d("com.thea.guo", "MainActivity.onTouchEvent is down");break;case MotionEvent.ACTION_MOVE:Log.d("com.thea.guo", "MainActivity.onTouchEvent is moving");break;case MotionEvent.ACTION_UP:Log.d("com.thea.guo", "MainActivity.onTouchEvent is up");break;}return super.onTouchEvent(event);}}
2.view代碼
/** * */package com.thea.guo.view;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.Button;import android.widget.TextView;/** * @author 子墨 * * 2015-1-15 */public class MyView extends TextView {public MyView(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:Log.d("com.thea.guo", "MyView.dispatchTouchEvent is down");break;case MotionEvent.ACTION_MOVE:Log.d("com.thea.guo", "MyView.dispatchTouchEvent is moving");break;case MotionEvent.ACTION_UP:Log.d("com.thea.guo", "MyView.dispatchTouchEvent is up");break;}return super.dispatchTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:Log.d("com.thea.guo", "MyView.onTouchEvent is down");break;case MotionEvent.ACTION_MOVE:Log.d("com.thea.guo", "MyView.onTouchEvent is moving");break;case MotionEvent.ACTION_UP:Log.d("com.thea.guo", "MyView.onTouchEvent is up");break;}return super.onTouchEvent(event);}}
3.ViewGroup代碼
/** * */package com.thea.guo.view;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.LinearLayout;/** * @author 子墨 * * 2015-1-15 */public class MyViewGroup extends LinearLayout {public MyViewGroup(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:Log.d("com.thea.guo", "MyViewGroup.dispatchTouchEvent is down");break;case MotionEvent.ACTION_MOVE:Log.d("com.thea.guo", "MyViewGroup.dispatchTouchEvent is moving");break;case MotionEvent.ACTION_UP:Log.d("com.thea.guo", "MyViewGroup.dispatchTouchEvent is up");break;}return super.dispatchTouchEvent(ev);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:Log.d("com.thea.guo", "MyViewGroup.onInterceptTouchEvent is down");break;case MotionEvent.ACTION_MOVE:Log.d("com.thea.guo", "MyViewGroup.onInterceptTouchEvent is moving");break;case MotionEvent.ACTION_UP:Log.d("com.thea.guo", "MyViewGroup.onInterceptTouchEvent is up");break;}return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:Log.d("com.thea.guo", "MyViewGroup.onTouchEvent is down");break;case MotionEvent.ACTION_MOVE:Log.d("com.thea.guo", "MyViewGroup.onTouchEvent is moving");break;case MotionEvent.ACTION_UP:Log.d("com.thea.guo", "MyViewGroup.onTouchEvent is up");break;}return super.onTouchEvent(event);}}
4.xml代碼
<com.thea.guo.view.MyViewGroup xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <com.thea.guo.view.MyView android:id="@+id/my_button" android:layout_width="200dp" android:layout_height="200dp" android:text="@string/hello_world" android:background="@android:color/holo_blue_bright"> </com.thea.guo.view.MyView></com.thea.guo.view.MyViewGroup>
以上就是全部代碼了,其實你還可以吧一部分代碼封裝一下更好,例如down,Move,up部分都是一樣的,你可以把這部分封裝.下面開始分析一下上文提到的特殊情況
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1.修改ViewGroup的dispatchTouchEvent(事件分發)返回值
(1)返回值為true
上面兩張圖片比較醒目的解釋了它的分發過程,首先從activity的dispatchTouchEvent開始分發,系統預設的情況下繼續分發,分發給ViewGroup的dispatchTouchEvent,ViewGroup的dispatchTouchEvent返回true,也就是說它對這個事件比較感興趣,它想留著自己處理,事件停止分發.
(2)返回值為false
同樣是從activity的dispatchTouchEvent開始分發,分發給ViewGroup的dispatchTouchEvent,ViewGroup的dispatchTouchEvent返回false,ViewGroup不感興趣,但是它也不配合你,他直接不給你往下傳遞了,這時候就需要onTouchEvent來處理了,由於view是從activity開始發起,所以就需要activity的OnTouchEvent來處理了
2.修改ViewGroup的onInterceptTouchEvent返回值
(1)返回值為true
還是從activity的dispatchTouchEvent開始分發,分發給ViewGroup的dispatchTouchEvent,ViewGroup判斷一下是否攔截,由於這裡onInterceptTouchEvent的返回值為true,不好意思它攔截了,它想讓它的OnTouchEvent處理這個事件,ViewGroup的OnTouchEvent處理完成後繼續向下傳遞給activity的OnTouchEvent
(2)返回值為false
是不是似曾相識啊,沒錯,ViewGroup中的onInterceptTouchEvent預設就是不攔截的,先從activity中的dispatchTouchEvent開始分發,分發給ViewGroup中的dispatchTouchEvent,然後判斷ViewGroup是否攔截,這裡返回false,表示它不攔截,然後繼續分發,分發給View中的dispatchTouchEvent,View下沒有子View了,於是他就直接給自己的onTouchEvent處理了,onTouchEvent對這個也不感興趣,繼續傳遞
3.修改View的dispatchTouchEvent返回值
(1)返回值為true
這裡還是那個分發過程,當分發到View時,它返回了true,也就是說它高度興趣,它想自己處理.
(2)返回值為false
還是那個配方還是那個味道,View中dispatchTouchEvent返回false,它直接不給分發了,留給OnTouch處理,由於view是從ViewGroup傳遞過來的,那也要ViewGroup的自個處理.
4.修改view中OnTouchEvent的返回值
(1)返回值為true
事件還是一如既往的傳遞,當傳遞到View中的OnTouchEvent時,返回true,它要say sorry了,不給你們傳遞了,到這它要自己處理了
(2)返回值為false
後面的OnTouchEvent跟view的都差不多了,這裡不再囉嗦,下面來個總結,結束這篇部落格
1.dispatchTouchEvent(事件分發)
當dispatchTouchEvent返回true時,由它自己處理
當dispatchTouchEvent返回false時,交給OnTouchEvent處理
系統預設的情況下,分發給onInterceptTouchEvent
2.onInterceptTouchEvent(事件攔截)
當onInterceptTouchEvent返回true,由他自己的OnTouchEvent處理
當onInterceptTouchEvent返回false,繼續分發
系統預設不攔截
3.onTouchEvent(事件響應)
當onTouchEvent返回true時自己處理
當onTouchEvent返回false,繼續傳遞
系統預設繼續傳遞
Android 事件分發