首先说明一个概念:正常情况下android中的事件,是必须要先经过传递流程然后再经过处理流程的,要记住这个先后顺序
在ViewGroup中,有下面3个方法:
- dispatchTouchEvent 该方法用来分发事件,一般不会重写这个方法
- onInterceptTouchEvent 该方法用来拦截事件
- onTouchEvent 该方法用来处理事件
在View中,只有2个方法:
- dispatchTouchEvent 该方法用来分发事件,一般不会重写这个方法
- onTouchEvent 该方法用来处理事件
事件列
- android事件是一些列的时间,从手机按下的down时间开始 经过一些列的move事件,最后是up事件
- 如果ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move,up等事件将继续会传递给该ViewGroup,之后才和down事件一样传递给目标view的onTouchEvent()来处理
- 如果ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move,up等事件将不再传递给该ViewGroup的onInterceptTouchEvent(),注意:目标view接收不到任何事件
下面用一个小demo来验证这些方法
这里我们使用两个自定义的ViewGroup和一个自定义的View来演示
public class ViewGroupA extends LinearLayout {
public ViewGroupB(Context context) {
super(context);
}
public ViewGroupB(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewGroupB(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("小付", "ViewGroupB dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("小付", "ViewGroupB onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
// return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("小付", "ViewGroupB onTouchEvent");
return super.onTouchEvent(event);
// return true;
}
}
public class ViewGroupB extends LinearLayout {
public ViewGroupB(Context context) {
super(context);
}
public ViewGroupB(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ViewGroupB(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("小付", "ViewGroupB dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("小付", "ViewGroupB onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
// return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("小付", "ViewGroupB onTouchEvent");
return super.onTouchEvent(event);
// return true;
}
}
public class MyView extends View {
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.e("小付", "MyView dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("小付", "MyView onTouchEvent");
// return super.onTouchEvent(event);
return true;
}
}
最后,把他们嵌套在一起,activity的布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.parade.myapplication.ViewGroupA
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#ff0033">
<com.parade.myapplication.ViewGroupB
android:layout_width="@dimen/dp_200"
android:layout_height="@dimen/dp_200"
android:gravity="center"
android:background="#336699">
<com.parade.myapplication.MyView
android:id="@+id/my_view"
android:layout_width="@dimen/dp_100"
android:layout_height="@dimen/dp_100"
android:background="#ffff33"/>
</com.parade.myapplication.ViewGroupB>
</com.parade.myapplication.ViewGroupA>
</LinearLayout>
布局截图如下:
从里到外依次是ViewGroupA,ViewGroupB和MyView,现在点击最里层的MyView,打印结果如下
默认在事件的传递和处理流程中,没有任何拦截
下面我们做实验,让MyView在事件处理过程中拦截事件,及其onTouch事件返回true,打印结果如下
可见ViewGroupA和ViewGroupB并没有处理事件,因为MyView已经拦截了事件处理
再来做一个实验,这次我们让ViewGroupB在事件传递过程中拦截,即其onInterceptTouchEvent 方法返回true,打印结果如下:
可见事件并没有传递到MyView,因为在ViewGroupB已经把事件传递拦截了