事件分发机制,简而言之就是Android对触摸事件的一系列传递和处理的机制。在了解分发机制之前需要对下面三个方法有个大概的了解:

  • public boolean dispatchTouchEvent(MotionEvent event)

用来进行事件的分发。如果有事件传递给当前View,那么此方法一定会被调用。返回值受当前View的onTouchEvent(MotionEvent event)和子ViewdispatchTouchEvent(MotionEvent event)方法的影响,表示是否消耗当前事件。

  • public boolean onInterceptTouchEvent(MotionEvent ev)

用来判断是否拦截事件,返回值表示是否拦截当前事件。

  • public boolean onTouchEvent(MotionEvent event)

用来处理事件,返回值表示是否消耗当前事件,如果不消耗,则在同一事件序列中,当前View无法再次接收到事件。

我们知道Android的View结构是树状结构的,View可以放在一个ViewGroup里,这个ViewGroup又可以放在一个ViewGroup里,那么当我们点击一个嵌套的结构,事件传递是怎样的呢?
为此,我们用代码来实现一下。

1.创建BaseViewGroup作为底层ViewGroup,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class BaseViewGroup extends FrameLayout {
public BaseViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("ViewEvent", "BaseViewGroup-dispatchTouchEvent-"+ev.getAction());
return super.dispatchTouchEvent(ev);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("ViewEvent", "BaseViewGroup-onInterceptTouchEvent-"+ev.getAction());
return super.onInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("ViewEvent", "BaseViewGroup-onTouchEvent-"+event.getAction());
return super.onTouchEvent(event);
}
}

2.创建TopViewGroup作为顶层ViewGroup,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class TopViewGroup extends FrameLayout {
public TopViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("ViewEvent", "TopViewGroup-dispatchTouchEvent-"+ev.getAction());
return super.dispatchTouchEvent(ev);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("ViewEvent", "TopViewGroup-onInterceptTouchEvent-"+ev.getAction());
return super.onInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("ViewEvent", "TopViewGroup-onTouchEvent-"+event.getAction());
return super.onTouchEvent(event);
}
}

3.创建MyView作为最上层的View,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyView extends View {
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("ViewEvent", "MyView-dispatchTouchEvent-"+ev.getAction());
return super.dispatchTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("ViewEvent", "MyView-onTouchEvent-"+event.getAction());
return super.onTouchEvent(event);
}
}

4.布局自定义ViewViewGroup,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<com.droidyu.viewsystem._3_event.BaseViewGroup 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="400dp"
android:layout_height="400dp"
android:background="#1f1"
tools:context="._3_event.ViewEventActivity">

<com.droidyu.viewsystem._3_event.TopViewGroup
android:background="#ff1"
android:layout_width="300dp"
android:layout_height="300dp" >

<com.droidyu.viewsystem._3_event.MyView
android:background="#f11"
android:layout_width="200dp"
android:layout_height="200dp" />
</com.droidyu.viewsystem._3_event.TopViewGroup>

</com.droidyu.viewsystem._3_event.BaseViewGroup>

最终,视图结构如下所示:

运行程序,点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,正常情况下,
事件的传递顺序是:
BaseViewGroup -> TopViewGroup -> MyViewdispatchTouchEventonInterceptTouchEvent方法
事件处理顺序是:
MyView -> TopViewGroup -> BaseViewGrouponTouchEvent方法

此时将BaseViewGrouponInterceptTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,BaseViewGroup拦截事件之后,就直接处理事件,不会再将事件向子View传递。

还原代码,将TopViewGrouponInterceptTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,事件从BaseViewGroup传递到TopViewGroupTopViewGroup拦截事件之后,就直接处理事件,不会再将事件向子View传递,处理后会不消耗,返回给BaseViewGroup再处理。

还原代码,将MyViewonTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,事件传递到MyViewMyView处理事件之后,就不再向上传递。

还原代码,将TopViewGrouponTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

Log日志可以看出,事件传递到MyViewMyView处理事件之后,又向上传递到TopViewGroup处理,TopViewGroup处理事件之后,就不再向上传递。

至此相信你对View的事件传递和处理有了一个更直观的认识,更多的讲解将在后续文章中更新,敬请期待。。。

源码见Github

关注我