一、Android触摸事件分发机制概述:
Android如此受欢迎,就在于其优秀的交互性,这其中,Android优秀的事件分发机制功不可没。那么,作为一个优秀的程序员,要想做一个具有良好交互性的应用,必须透彻理解Android的事件分发机制。
要想充分理解android的分发机制,需要先对以下几个知识点有所了解:
① View和ViewGroup什么?
② 事件
③ View 事件的分发机制
④ ViewGroup事件的分发机制
下面,就让我们沿着大致方针,开始事件分发的探究之旅吧……
二、View和ViewGroup:
Android的UI界面都是由View和ViewGroup及其派生类组合而成的。其中,View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的,也就是说ViewGroup的父类就是View。
通常来说,Button、ImageView、TextView等控件都是继承父类View来实现的。RelativeLayout、LinearLayout、FrameLayout等布局都是继承父类ViewGroup来实现的。
事件:
当手指触摸到View或ViewGroup派生的控件后,将会触发一系列的触发响应事件,如:
onTouchEvent、onClick、onLongClick等。每个View都有自己处理事件的回调方法,开发人员只需要重写这些回调方法,就可以实现需要的响应事件。
而事件通常重要的有如下三种:
MotionEvent.ACTION_DOWN 按下View,是所有事件的开始
MotionEvent.ACTION_MOVE 滑动事件
MotionEvent.ACTION_UP 与down对应,表示抬起
三、事件传递的三个阶段
1> 事件分发(dispatch):事情的分发对应着dispatchTouchEvent方法,android系统中,所有的触摸事件都是通过这个方法来分发的,方法原型如 下:public boolean dispatchTouchEvent(MotionEvent ev)
方法返回值为true表示事件被当前视图消费掉,不在分发事件;方法返回值为super.dispatchTouchEvent表示继续分发该事件 。如果当前视图是ViewGroup及其子类,则会调用onInterceptTouchEvent方法判定是否拦截该事件。
2> 事件拦截(Intercept):事件的拦截对应着onInterceptTouchEvent方法,这个方法只在ViewGroup及其子类中才存在,在View和Activity中是不存在的。方法的原形如下:public boolean onInterceptTouchEvent(MotionEvent ev)
方法返回true表示拦截事件,不继续分发给子视图,同时交由自身的onTouchEvent方法进行消费,返回false或super.onInterceptTouchEvent
表示不对事件进行拦截,需要继续传递给子视图
3> 消费(Consume):事件的消费对应着onTouchEvent方法,方法原型为
public boolean onTouchEvent(MotionEvent event)
方法返回值为false表示当前视图不处理这个事件,处理会被传递给父视图的onTouchEvent方法进行处理。
在android系统中,拥有事件传递处理能力的类有以下三种
Activity:拥有dispatchTouchEvent(Activity的dispatchTouchEvent放回的如果是true或false的时候将不会继续分发事件)和onTouchEvent两个 方法
ViewGroup:拥有dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent三个方法
View:拥有dispatchTouchEvent和onTouchEvent两个方法
四、触摸事件传递的传递顺序如下:
触摸事件的传递顺序是由Activity到ViewGroup,再由ViewGroup递归传递给它的子View。
ViewGroup通过onIterceptTouchEvent方法针对事件进行拦截,如果该方法返回true,则事件不会继续传递给子View,如果返回false或者
super.onInterceptTouchEvent,则事件会继续传递给子View。
在子View中对事件进行消费后,ViewGroup将接收不到任何事件。
五、TouchEvent事件传递顺序
1
2
3
|
dispatchTouchEvent 事件的分发操作
TouchEvent 事件处理
onInterceptTouchEvent 事件拦截操作
|
在Activity与View中,TouchEvent的传递会先经过 dispatchTouchEvent,然后再到onTouchEvent
在ViewGroup中,有点特殊,在dispatchTouchEvent与onTouchEvent之间,还会经过onInterceptTouchEvent这个方法
1
2
3
4
5
6
7
8
|
MotionEvent.ACTION_DOWN的传递
①Activity.dispatchTouchEvent
②ViewGroup.dispatchTouchEvent
③ViewGroup.onInterceptTouchEvent
④View.dispatchTouchEvent
⑤View.onTouchEvent (如果这里返回
true
,后续的MOVE,UP事件都会传递到这里处理,否则继续向下传递)
⑥ViewGroup.onTouchEvent (如果这里返回
true
,后续的MOVE,UP事件会通过ViewGroup.dispatchTouchEvent都会直接传递到这里处理,不在向下传递,否则继续向下传递)
⑦Activity.onTouchEvent (如果事件经过了GroupView,View,还是传到了这里,不管这里返回的是
false
还是
true
,后续的MOVE,UP事件都会直接通过Activity.dispatchTouchEvent传递到这里)
|
dispatchTouchEvent方法测试 1
1
2
3
4
|
@Override
public
boolean
dispatchTouchEvent(MotionEvent event) {
return
(
true
||
false
);
// 直接返回true或者false
}
|
经测试在dispatchTouchEvent方法,如果没有super.dispatchTouchEvent(event)也就是没有继续父类的实现,
这里返回true,那么事件都会传到这里结束。
这里返回false,事件会直接抛到上一层的onTouchEvent事件中
{ // 说明
在Activity的dispatchTouchEvent返回false,事件直接结束
在ViewGroup的dispatchTouchEvent返回false,事件会直接传递到Activity.onTouchEvent中
在View的dispatchTouchEvent返回false,事件会直接传递到ViewGroup.onTouchEvent中
}
dispatchTouchEvent方法测试 2
1
2
3
4
5
|
@Override
public
boolean
dispatchTouchEvent(MotionEvent event) {
super
.dispatchTouchEvent(event);
return
(
true
||
false
);
// 直接返回true或者false
}
|
测试在dispatchTouchEvent方法中加上super.dispatchTouchEvent(event)这一行
这里返回true,事件会像常规一样去传递,但是最终会传到这一层的onTouchEvent结束,相当于本层的onTouchEvent返回了true
这里返回false,事件会像常规一样去传递,最终于会在哪一层的onTouchEvent返回true结束,随便事件就会直接到那一层的onTouchEvent
ViewGroup.onInterceptTouchEvent
在这个方法中,返回true事件将会被拦截直接传递到ViewGroup的onTouchEvent中处理
在这个方法中,返回false事件向常规一样处理