MainActivity如下:
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>
时间: 2024-10-06 07:18:52