Android的兩種控件View和ViewGroup
ViewGroup可以有子控件,如:LinearLayout,ListView
View也就是普通控件,沒有子布局,如:TextView Button
事件分發(fā)需要了解的三個方法
ViewGroup的dispatchTouchEvent, onInterceptTouchEvent和onTouchEvent
1)public boolean dispatchTouchEvent(MotionEvent ev) 這個方法用來分發(fā)TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 這個方法用來攔截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 這個方法用來處理TouchEvent
View的dispatchTouchEvent和onTouchEvent
1)public boolean dispatchTouchEvent(MotionEvent ev) 這個方法用來分發(fā)TouchEvent
2)public boolean onTouchEvent(MotionEvent ev) 這個方法用來處理TouchEvent
對于一個ViewGroup來說
點擊事件首先是調(diào)用dispatchTouchEvent。
如果這這個ViewGroup的onInterceptTouchEvent返回true就表示它要攔截此事件,接著這個ViewGroup的onTouchEvent就會被調(diào)用。
如果這個ViweGroup的onInterceptTouch返回false,那么就會繼續(xù)向下調(diào)用子控件的dipatchTouchEvent。
對于View來說
事件傳遞機制有兩個函數(shù):dispatchTouchEvent負責(zé)分發(fā)事件,在dispatch***里又會調(diào)用onTouchEvent表示執(zhí)行事件。
或者說消費事件,結(jié)合源碼分析其流程。事件傳遞的入口是View的dispatchTouchEvent()函數(shù).
1、事件入口是dispatchTouchEvent(),它會先執(zhí)行注冊的onTouch監(jiān)聽,如果一切順利的話,接著執(zhí)行onTouchEvent,在onTouchEvent里會執(zhí)行onClick監(jiān)聽。
2、無論是dispatchTouchEvent還是onTouchEvent,如果返回true表示這個事件已經(jīng)被消費、處理了,不再往下傳了。在dispathTouchEvent的源碼里可以看到,如果onTouchEvent返回了true,那么它也返回true。如果dispatch***在執(zhí)行onTouch監(jiān)聽的時候,onTouch返回了true,那么它也返回true,這個事件提前被onTouch消費掉了。就不再執(zhí)行onTouchEvent了,更別說onClick監(jiān)聽了。
3、我們通常在onTouch監(jiān)聽了設(shè)置圖片一旦被觸摸就改變它的背景、透明度之類的,這個onTouch表示事件的時機。而在onClick監(jiān)聽了去具體干某些事。
4、什么時候不會走onTouchEvent呢?當(dāng)重寫dispatchTouchEvent,不走super.dispatchTouchEvent直接返回false,它就不會走onTouchEvent。當(dāng)然這樣做是違反android架構(gòu)常理的,一般的dispatchTouchEvent是不建議重寫的。不過通過這個案例我們可以總結(jié)出這么一個結(jié)論.
5、在事件到達view的時候,先走dispatchTouchEvent,在系統(tǒng)的dispatchTouchEvent中它會調(diào)用該view的Ontouch方法如果此onTouch方法的down事件里返回true,則dispatchTouchEvent方法也返回true,且把以后的move事件,up事件都傳給onTouch。之后的move事件及up事件的返回值,onTouch返回什么dispatchTouchEvent也返回什么。相反如果傳第一個down事件給ontouch的時候,ontouch返回的是false,從此事件不再會傳過來,也就是不會走dispatchTouchEvent。更不會走ontouchevent,相反如果傳第一個down事件給ontouch的時候,ontouch返回的是false,從此事件不再會傳過來,也就是不會走dispatchTouchEvent。更不會走ontouchevent
下面結(jié)合源碼來分析
自定義控件ViewGropu為MyLinearLayout
package com.project1.View;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
/**
* Created by Administrator on 2017/1/5.
*/
public class MyLinearLayout extends LinearLayout {
private final String TAG = "MyLinearLayout";
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(TAG, TAG);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "dispatchTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "dispatchTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "dispatchTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "dispatchTouchEvent action:ACTION_CANCEL");
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "onInterceptTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "onInterceptTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "onInterceptTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "onInterceptTouchEvent action:ACTION_CANCEL");
break;
}
return true;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "---onTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "---onTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "---onTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "---onTouchEvent action:ACTION_CANCEL");
break;
}
return false;
}
}
自定義控件View為MyTextView
package com.project1.View;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;
public class MyTextView extends TextView {
private final String TAG = "MyTextView";
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "dispatchTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "dispatchTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "dispatchTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "onTouchEvent action:ACTION_CANCEL");
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "---onTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "---onTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "---onTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "---onTouchEvent action:ACTION_CANCEL");
break;
}
return false;
}
}
當(dāng)MyLinearLayout中的dispatchTouchEvent為true時

當(dāng)MyLinearLayout
- onInterceptTouchEvent為false,
- onTouchEvent為true
當(dāng)MyTextView中
-
onTouchEvent為true
onTouchEvent完全由MyTextView處理
當(dāng)MyLinearLayout中
- onInterceptTouchEvent為false
- onTouchEvent為false
MyTextView中
-
onTouchEvent為true
onTouchEvent完全由MyTextView處理,基本和上面一致
當(dāng)MyLinearLayout中
- onInterceptTouchEvent為false
- onTouchEvent為true
當(dāng)MyTextView中
-
onTouchEvent為false
MyTextView只處理了ACTION_DOWN事件其他完全由MyLinearLayout的onTouchEvent處理
當(dāng)MyLinearLayout中
- onInterceptTouchEvent為false
- onTouchEvent為false
當(dāng)MyTextView中
-
onTouchEvent為false
都只處理了ACTION_DOWN事件
****onInterceptTouchEvent為ture(時)無需理會子控件的値****
當(dāng)MyLinearLayout中
- onInterceptTouchEvent為ture
-
onTouchEvent為true
MyLinearLayout自己處理所有的onTouchEvent事件
當(dāng)MyLinearlayout中
- onInterceptTouchEvent為true
-
onTouchEvent為false;
MyLinearLayout只處理了ACTION_DOWN事件





