布局文件如下:
<RelativeLayout 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"
tools:context="com.example.viewdispatch.MainActivity" >
<com.example.views.MyViewGroupA
android:layout_width="260dp"
android:layout_height="360dp"
android:background="#f42c61" >
<com.example.views.MyViewGroupB
android:layout_width="200dp"
android:layout_height="300dp"
android:background="#042c61" >
<com.example.views.MyView
android:layout_width="160dp"
android:layout_height="260dp"
android:background="#cccccc" />
</com.example.views.MyViewGroupB>
</com.example.views.MyViewGroupA>
</RelativeLayout>
整体的Activity包含3个自定义的View,项目结构是MyView、MyViewGroupB、MyViewGroupA。所以整体Touch事件的主角是View和ViewGroup,而与View相关的Touch事件有2个dispatchTouchEvent和onTouchEvent;与ViewGroup相关的Touch事件有3个dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent。所以我们在定义好View和ViewGroup后,让其分别是实现这些方法。
代码如下:
MyView.java
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class MyView extends View {
private String Tag = "MyView";
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(Tag, "----->MyView");
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e(Tag, "----->onTouchEvent");
return super.onTouchEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.e(Tag, "----->dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
}
MyViewGroupA.java```
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.LinearLayout;
public class MyViewGroupA extends LinearLayout {
private String Tag = "MyViewGroupA";
public MyViewGroupA(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO 自动生成的构造函数存根
}
public MyViewGroupA(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(Tag, "----->MyViewGroupA");
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e(Tag, "----->dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e(Tag, "----->onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e(Tag, "----->onTouchEvent");
return super.onTouchEvent(event);
}
}
MyViewGroupB和A一样,就不贴了。
其中上面事件的传递的返回值是这样的,如果返回true,表示该View(ViewGroup)拦截了,不继续往下分发事件了,如果返回false,表示不拦截,继续往下分发。默认的调用父方法super.xxx是表示不拦截的意思。
下面就开始来验证吧。
运行我们的项目,先看看我们3个view的加载情况吧:

可以看出是由外到内加载的。
好了,开始touch事件吧,现在我们先点击最外层粉红的ViewGroupA,观察Log输出:

然后点击蓝色区域的ViewGroupB,再观察Log输出:

最后点击MyView观察输出

由此,我们可以大致的绘制出如下图所示的这样的一个图解流程。