事件分发机制,简而言之就是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
关注我