Android View事件分发机制
来源:互联网 发布:淘宝网店做什么好 编辑:程序博客网 时间:2024/05/21 17:18
iew的事件分发机制说白了就是点击事件的传递,也就是一个Down事件,若干个Move事件,一个Up事件构成的事件序列的传递。
当你手指按了屏幕,点击事件就会遵循Activity->Window→View这一顺序传递。
这一传递过程有三个重要的方法,分别是:
- boolean dispatchTouchEcent(MotionEvent ev),
- boolean onInterceptTouchEvent(MotionEvent event),
- boolean onTouchEvent(MotionEvent event)
先一个一个简单介绍下:
dispatchTouchEcent:
只要事件传递到了当前View,那么dispatchTouchEcent方法就一定会被调用。返回结果表示是否消耗当前事件。
onInterceptTouchEvent:
在dispatchTouchEcent方法内部调用此方法,用来判断是否拦截某个事件。如果当前View拦截了某个事件,那么在这同一个事件序列中,此方法不会再次被调用。返回结果表示是否拦截当前事件。
onTouchEvent:
在dispatchTouchEcent方法内调用此方法,用来处理事件。返回结果表示是否处理当前事件,如果不处理,那么在同一个事件序列里面,当前View无法再收到后续的事件。
当点击事件传递到根ViewGroup里,会执行dispatchTouchEvent,在其内部会先调用onInterceptTouchEvent询问是否拦截事件,若拦截,则执行onTouchEvent方法处理这个事件;
若不拦截,则执行子元素的dispatchTouchEvent,进入向下分发的传递,直到事件被处理。
在处理一个事件的时候,是有优先级的,如果设置了OnTouchListener,会先执行其内部的onTouch方法,这时若onTouch方法返回true,那么表示事件被处理了,不会向下传递了;
如果返回了false,那么事件会继续传递给onTouchEvent方法处理,在onTouchEvent方法中如果当前设置了OnClickListener,那么就会调用其onClick方法。
所以其优先级为:OnTouchListen>onTouchEvent>OnClickListen。
这里有一种情况,如果一个View的onTouchEvent返回了false,那么它父容器的onTouchEvent方法将会被调用。
既然如此,在开头我们说过事件的传递顺序是Activity->Window→View,所以如果所有的元素都返回了false,那么最后事件就会再次传递到Activity里,由Activity的onTouchEvent方法来处理。
这三种方法的对比:
简单举例:
单击button时,会输出log如下:
可以看到,不管是DOWN,MOVE,UP都会按照下面的顺序执行:
1、dispatchTouchEvent
2、 setOnTouchListener的onTouch
3、onTouchEvent
View的dispatchTouchEvent的源码:
从源码可以看出:
首先判断mOnTouchListener不为null,并且view是enable的状态,然后 mOnTouchListener.onTouch(this, event)返回true,这三个条件如果都满足,直接return true ; 也就是下面的onTouchEvent(event)不会被执行了;
View的onTouchEvent的源码:
在MotionEvent.ACTION_UP 有一个重要的方法
看到了平时使用最多的监听器OnClickListener,有木有很激动!可以看到,只要mOnClickListener不是null,就会去调用它的onClick方法;同时根据事件响应先后顺序,可以知道OnTouchListener会在OnClickListener之前响应,如果 onTouchEvent 直接返回true时,OnClickListener就不会执行了。
ViewGroup的事件分发机制
先看一个例子:
对应activity的布局文件是:
点击按钮时,日志如下:
MyLinearLayout的dispatchTouchEvent -> MyLinearLayout的onInterceptTouchEvent -> MyButton的dispatchTouchEvent ->Mybutton的onTouchEvent
可以看出,在View上触发事件,最先捕获到事件的为View所在的ViewGroup,然后才会到View自身
让我们从源码一看究竟
ViewGroup - dispatchTouchEvent - ACTION_DOWN
ViewGroup的事件拦截
复写ViewGroup的onInterceptTouchEvent方法:
如何不被拦截:
requestDisallowInterceptTouchEvent(boolean) 用于设置是否允许拦截,我们在子View的dispatchTouchEvent中直接这么写:
总结:
1、如果ViewGroup找到了能够处理该事件的View,则直接交给子View处理,自己的onTouchEvent不会被触发;
2、可以通过复写onInterceptTouchEvent(ev)方法,拦截子View的事件(即return true),把事件交给自己处理,则会执行自己对应的onTouchEvent方法
3、子View可以通过调用getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup对其MOVE或者UP事件进行拦截;
应用场景:
滑动冲突的处理
滑动冲突的基本形式分为两种,其他复杂的滑动冲突都可以拆成这两种基本形式:
1:外部滑动方向与内部方向不一致。
2:外部方向与内部方向一致。
滑动冲突的拦截方法有两种:
一种是让事件都经过父容器的拦截处理,如果父容器需要则拦截,如果不需要则不拦截,称为外部拦截法
在这里,首先down事件父容器必须返回false ,因为若是返回true,也就是拦截了down事件,那么后续的move和up事件就都会传递给父容器,子元素就没有机会处理事件了。
其次是up事件也返回了false,一是因为up事件对父容器没什么意义,其次是因为若事件是子元素处理的,却没有收到up事件会让子元素的onClick事件无法触发。
另一种是父容器不拦截任何事件,将所有事件传递给子元素,如果子元素需要则消耗掉,如果不需要则通过requestDisallowInterceptTouchEvent方法交给父容器处理,称为内部拦截法
- android View事件分发机制。
- Android View事件分发机制
- android view事件分发机制
- Android View 事件分发机制
- Android:View事件分发机制
- Android事件分发机制-------View
- Android View事件分发机制
- android事件分发机制view
- Android View 事件分发机制
- Android View事件分发机制
- Android View 事件分发机制
- Android View事件分发机制
- Android View事件分发机制
- android事件分发机制 VIew的事件分发机制
- Android 事件分发机制解析之View的事件分发
- Android View 事件分发机制 源码解析
- Android View、ViewGroup 事件分发机制(一)
- Android View、ViewGroup 事件分发机制(二)
- 一个能跑起来的ssh小项目
- 正则
- charles破解
- Objective-C 中nil Nil NULL NSNull 之间的区别
- hdu4160 Dolls【最小路径覆盖】
- Android View事件分发机制
- 将树形结构的数据转换为二维数组 (续 PHP非递归方式实现无限分类(转载))
- iOS自动打包并发布脚本
- 有返回结果的界面跳转
- 微信的分享文本,音频,视频,链接,表情,图片功能
- USB mass storage协议
- Android NDK 较完整的总结
- redis中 sCard 和 sSize 有什么区别?
- USB驱动开发之mass storage的枚举识别过程