MainActivity如下:
MyLinearLayout如下:
MyButton如下:
main.xml如下:
package cn.c;
import android.os.Bundle;
import android.app.Activity;
import android.view.MotionEvent;
/**
* Demo描述:
* 分析Android事件分发和处理机制
*
*
* 总结:
* 1 ViewGroup继承自View
* 事件的传递方向为:从最外层(Activity)传递至最内层(某个View)
* 事件的消费方向为:从最内层(某个View)传递至最外层(Activity)
* 该两个方向是相反的
* 2 ViewGroup中事件处理的流程是:
* dispatchTouchEvent->onInterceptTouchEvent->onTouchEvent
* View中事件处理的流程是:
* dispatchTouchEvent->onTouchEvent
* 3 ViewGroup中onInterceptTouchEvent默认值是false
* 表示未拦截
* ViewGroup中onTouchEvent默认值是false
* 表示未消费
* View中onTouchEvent返回默认值是true
* 表示已消费
*
* 小结:
* (1) 每一次的ACTION_DOWN和ACTION_MOVE以及ACTION_UP都会引起每一层的dispatchTouchEvent()
* 所以:dispatchTouchEvent()的顺序是由上至下的!!!!!!!!!!!!!!!
* (2) 但是每一层的onTouchEvent()就不一定会执行了.比如下层已经消耗掉了事件,那么上层就不会响应onTouchEvent()了.
* 所以:onTouchEvent()是从下到上回溯的.当然前提是事件没有被消费的情况下!!!!!!!!!!!!!
*
* 在该示例中涉及到三个自定义的View.分别是:
* 最外层的布局MyFrameLayout
* 内层的布局MyLinearLayout
* 最里层的自定义按钮MyButton
*
* 现在进行一系列的测试并对现象进行解释
*
* 测试一:
* 在MyFrameLayout的dispatchTouchEvent()方法中直接返回false.
* 那么可以看到MyFrameLayout的onInterceptTouchEvent()和onTouchEvent()都没有执行.
* MyFrameLayout所包含的子View对于Touch事件也当然没有任何的反映.
* 其实这样直接返回false是挺残暴的.因为重写了该方法,使得源码中dispatchTouchEvent()方法里的
* 一大堆代码都没有执行,所以它的onInterceptTouchEvent()和onTouchEvent()都没有调用也就没有
* 什么事件的继续分发了.
* 因为它直接给Activity返回了false即连ACTION_DOWN事件都没有处理.所以后续的事件比如ACTION_DOWN和ACTION_UP
* 都没有资格处理,都是直接由Activity处理了.
*
*
* 测试二:
* 在MyFrameLayout的dispatchTouchEvent()方法中调用:super.dispatchTouchEvent(ev);
* 且返回return super.dispatchTouchEvent(ev);
* 在MyFrameLayout的onInterceptTouchEvent()方法中直接返回return true;表示拦截
* 可以看到事件的分发到了MyFrameLayout就停止了,不会向其子View派发.
*
* 其余的验证将在下一个例子中给出.
*
*/
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
System.out.println("===> MainActivity 中调用 onCreate()");
System.out.println("--------------------------------------------------");
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
System.out.println("===> MainActivity 中调用 dispatchTouchEvent()");
System.out.println("===> super.dispatchTouchEvent()默认返回true");
System.out.println("--------------------------------------------------");
return super.dispatchTouchEvent(ev);
}
@Override
public void onUserInteraction() {
System.out.println("===> MainActivity 中调用 onUserInteraction()");
System.out.println("--------------------------------------------------");
super.onUserInteraction();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("===> MainActivity 中调用 onTouchEvent()--->ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("===> MainActivity 中调用 onTouchEvent()--->ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("===> MainActivity 中调用 onTouchEvent()--->ACTION_UP");
default:
break;
}
System.out.println("super.onTouchEvent()默认返回false 表示未消费事件");
System.out.println("--------------------------------------------------");
return super.onTouchEvent(event);
}
}
MyFrameLayout如下:
package cn.c;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
public class MyFrameLayout extends FrameLayout{
public MyFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//super.dispatchTouchEvent(ev);
System.out.println("外层MyFrameLayout 中调用 dispatchTouchEvent()");
System.out.println("super.dispatchTouchEvent()默认返回true 表示继续分发");
System.out.println("--------------------------------------------------");
return super.dispatchTouchEvent(ev);
//return false;
}
//覆写自ViewGroup
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
System.out.println("外层MyFrameLayout 中调用 onInterceptTouchEvent()");
System.out.println("super.onInterceptTouchEvent()默认返回false 表示不拦截");
System.out.println("--------------------------------------------------");
//return super.onInterceptTouchEvent(ev);
return true;
}
//注意:
//1 ViewGroup是View的子类
//2 ViewGroup中onTouchEvent()方法默认返回的是false
@Override
public boolean onTouchEvent(MotionEvent event) {
//super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("外层MyFrameLayout 中调用 onTouchEvent()--->ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("外层MyFrameLayout 中调用 onTouchEvent()--->ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("外层MyFrameLayout 中调用 onTouchEvent()--->ACTION_UP");
default:
break;
}
System.out.println("super.onTouchEvent()默认返回false 表示未消费事件");
System.out.println("--------------------------------------------------");
return super.onTouchEvent(event);
//return true;
}
}
MyLinearLayout如下:
package cn.c;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//super.dispatchTouchEvent(ev);
System.out.println("内层MyLinearLayout 中调用 dispatchTouchEvent()");
System.out.println("super.dispatchTouchEvent()默认返回true 表示继续分发");
System.out.println("--------------------------------------------------");
//return super.dispatchTouchEvent(ev);
return false;
}
//覆写自ViewGroup
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//super.onInterceptTouchEvent(ev);
System.out.println("内层MyLinearLayout 中调用 onInterceptTouchEvent()");
System.out.println("super.onInterceptTouchEvent()默认返回false 表示不拦截");
System.out.println("--------------------------------------------------");
return super.onInterceptTouchEvent(ev);
}
//注意:
//1 ViewGroup是View的子类
//2 ViewGroup中onTouchEvent()方法默认返回的是false
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("内层MyLinearLayout 中调用 onTouchEvent()--->ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("内层MyLinearLayout 中调用 onTouchEvent()--->ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("内层MyLinearLayout 中调用 onTouchEvent()--->ACTION_UP");
default:
break;
}
System.out.println("super.onTouchEvent()默认返回false 表示未消费事件");
System.out.println("--------------------------------------------------");
return super.onTouchEvent(event);
}
}
MyButton如下:
package cn.c;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;
public class MyButton extends Button{
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
System.out.println("自定义Button 中调用 dispatchTouchEvent()");
System.out.println("super.dispatchTouchEvent默认返回true");
System.out.println("--------------------------------------------------");
return super.dispatchTouchEvent(event);
}
//注意:
//在View的子类中onTouchEvent()方法默认返回的是true
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("自定义Button 中调用 onTouchEvent()--->ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
System.out.println("自定义Button 中调用 onTouchEvent()--->ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
System.out.println("自定义Button 中调用 onTouchEvent()--->ACTION_UP");
break;
default:
break;
}
System.out.println("super.onTouchEvent()默认返回true");
System.out.println("--------------------------------------------------");
return super.onTouchEvent(event);
}
}
main.xml如下:
<!-- 自定义布局中,放置一个自定义控件 -->
<cn.c.MyFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<cn.c.MyLinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<cn.c.MyButton
android:layout_width="200dip"
android:layout_height="200dip"
android:text="自定义Button"
android:textColor="@android:color/black"
/>
</cn.c.MyLinearLayout>
</cn.c.MyFrameLayout>