推荐:非著名程序员的安卓自定义View教程目录,我的自定义view就是看他的这个系列学会的
首先,我们需要确认的是android的事件传递机制是责任链模式,如果自己能处理就拦截下来自己处理,如果自己处理不了或者不确定就传递给下一个对象
事件的拦截、分发、消费
我们要知道三个方法,控制事件反而拦截,分发与消费。如下表:
类型 | 相关方法 | Activity | ViewGroup | View |
---|---|---|---|---|
事件分发 | dispatchTouchEvent | 有 | 有 | 无 |
事件拦截 | onInterceptTouchEvent | 无 | 有 | 无 |
事件处理 | onTouchEvent | 有 | 有 | 有 |
以上三个方法,均有boolean类型的返回值,通过设置true,false来控制事件传递的流程
Activity和View均没有事件拦截方法,是因为
Activity作为事件响应起点,如果,Activity把事件拦截了,辣么将为导致整个屏幕都无法点击
View作为事件响应的最末端,要么消费事件,要么不处理回传,没必要拦截事件
事件分发流程
先给出一张图
这里,我们看到多了两个东西,一个是PhoneWindow,一个是DecorView,我们平时写的布局,最外层的父布局就是这里的RootView,有过几个app开发经验的程序员都应该知道,app的状态栏颜色的修改,还有那个主题的内容修改,修改后显示在哪呢?没错,就是DecorView里面。
再有就是phoneWindow,其实,知不知道没什么用,phonewindow是Window的唯一实现类,Window是干嘛的呢?Window是一个抽象类,所有的视图,事件传递都归它管理,所以,phonewindow管理视图,上面说的DecorView就是phonewindow的一个内部实现类,除了自己的功能外,还负责消息传递。
说了这么多,该来讲讲事件传递的流程了。android的view是树形结构的,基于这样的结构,我们的事件可以有序的分发。事件收集之后,起点是Activity,然后有序的向下传递,大致如下:
Activity -> PhoneWindow -> DecorView -> ViewGroup -> ... -> View
如果这个事件没有对象处理,辣么,它会依次往回传递,如果还是没有人处理,辣么就会被Activity抛弃掉
Activity <- PhoneWindow <- DecorView <- ViewGroup <- ... <- View
这就是文章开头我们提到的,责任链模式
下面我给出ViewGroup的事件分发机制的伪代码:
1 | public boolean dispatchTouchEvent(MotionEvent ev) { |
情景:老板: 我看公司最近业务不咋地,准备发展一下电商业务,下周之前做个淘宝出来试试怎么样。
事件顺序,老板(MainActivity)要做淘宝,这个事件通过各个部门(ViewGroup)一层一层的往下传,传到最底层的时候,码农小王(View1)发现做不了,于是消息又一层一层的回传到老板那里。
可以看到整个事件传递路线非常有序。从Activity开始,最后回传给Activity结束(由于我们无法操作Phone Window和DecorView,所以没有它们的信息)。
1 |
|
总结
事件分发机制设计到到情形非常多,这里就不一一列举了,记住以下几条原则就行了。
如果事件被消费,就意味着事件信息传递终止。
如果事件一直没有被消费,最后会传给Activity,如果Activity也不需要就被抛弃。
判断事件是否被消费是根据返回值,而不是根据你是否使用了事件。