事件分发机制,简而言之就是Android对触摸事件的一系列传递和处理的机制。在了解分发机制之前需要对下面三个方法有个大概的了解:
public boolean dispatchTouchEvent(MotionEvent event)
用来进行事件的分发。如果有事件传递给当前View,那么此方法一定会被调用。返回值受当前View的onTouchEvent(MotionEvent event)和子View的dispatchTouchEvent(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.布局自定义View及ViewGroup,代码如下:
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 -> MyView 的dispatchTouchEvent和onInterceptTouchEvent方法
事件处理顺序是:
MyView -> TopViewGroup -> BaseViewGroup 的onTouchEvent方法
此时将BaseViewGroup的onInterceptTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

从Log日志可以看出,BaseViewGroup拦截事件之后,就直接处理事件,不会再将事件向子View传递。
还原代码,将TopViewGroup的onInterceptTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

从Log日志可以看出,事件从BaseViewGroup传递到TopViewGroup,TopViewGroup拦截事件之后,就直接处理事件,不会再将事件向子View传递,处理后会不消耗,返回给BaseViewGroup再处理。
还原代码,将MyView的onTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

从Log日志可以看出,事件传递到MyView,MyView处理事件之后,就不再向上传递。
还原代码,将TopViewGroup的onTouchEvent返回值改为true,再次点击红色的MyView,然后查看Log日志如下:

从Log日志可以看出,事件传递到MyView,MyView处理事件之后,又向上传递到TopViewGroup处理,TopViewGroup处理事件之后,就不再向上传递。
至此相信你对View的事件传递和处理有了一个更直观的认识,更多的讲解将在后续文章中更新,敬请期待。。。
源码见Github
关注我