- 父类拦截DOWN事件后,所有事件无法传递给子类
- onTouchListener先于onTouchEvent,onTouchListener返回true不会执行onTouchEvent
- requestDisallowInterceptTouchEvent 子元素拦截父dispatch,父类intercept返回true也无效,down事件除外
MotionEvent
系统有一个线程在循环收集屏幕硬件信息,当用户触摸屏幕时,该线程会把从硬件设备收集到的信息封装成一个MotionEvent对象,然后把该对象存放到一个消息队列中。
系统的另一个线程循环的读取消息队列中的MotionEvent,然后交给WMS去派发,WMS把该事件派发给当前处于活动的Activity,即处于活动栈最顶端的Activity。
这就是一个先进先出的消费者和生产者的模板,一个线程不停的创建MotionEvent对象放入队列中,另一个线程不断的从队列中取出MotionEvent对象进行分发。
当用户的手指从接触屏幕到离开屏幕,是一个完整的触摸事件,在该事件中,系统会不断收集事件信息封装成MotionEvent对象。收集的间隔时间取决于硬件设备,例如屏幕的灵敏度以及cpu的计算能力。目前的手机一般在20毫秒左右。
MotionEvent事件
ACTION_DOWN ——> 表示按下了屏幕,一个事件必然从ACTION_DOWN开始
ACTION_MOVE ——> 表示移动手势
ACTION_UP ——> 表示离开屏幕
ACTION_CANCEL ——> 表示取消手势,一般由程序产生,不会由用户产生
一个ACTION_DOWN, n个ACTION_MOVE,1个ACTION_UP,就构成了Android中众多的事件。
Android中的事件onClick, onScroll, onFling等等,都是由许多个Touch组成的。
一个原则,所有的touch事件都是从父容器开始向下传递的,呈U字形。
MotionEvent中的坐标:
- getRawX:触摸点相对于屏幕的坐标
- getX: 触摸点相对于按钮的坐标
- getTop: 按钮左上角相对于父view(LinerLayout)的y坐标
- getLeft: 按钮左上角相对于父view(LinerLayout)的x坐标
OnTouchListener & onTouch
public boolean dispatchTouchEvent(MotionEvent event) {//返回true,表示该View内部消化掉了所有事件。返回false,表示View内部只处理了ACTION_DOWN事件,事件继续传递,向上级View(ViewGroup)传递。
...
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {//此处的onTouch方式就是回调的我们注册OnTouchListener时重写的onTouch()方法
return true;
}
if (onTouchEvent(event)) {// onTouchEvent参考下面源码
return true;
}
...
}
OnTouchListener不为null(即给view注册了OnTouchListener)——> 重写的onTouch()方法中返回false ——> 执行onTouchEvent方法 ——> 当前控件是ENABLED状态——> onClick()回调方法执行
OnTouchListener不为null ——> 重写的onTouch()方法返回true ——> onTouchEvent方法不执行 ——> onClick()回调方法不会执行
OnTouchListener为null ——> 执行onTouchEvent方法 ——> 当前控件是ENABLED状态——> onClick()回调方法执行
OnTouchListener为null ——> 执行onTouchEvent方法 ——> 当前控件不是ENABLED状态——> onClick()回调方法不会执行
整理自:https://blog.csdn.net/wuseyukui/article/details/46523899
网友评论