温故而知新,系统整理一下。
1. View是什么?
1. 触摸事件的基本类型
1). down: 按下
2). move: 移动
3). up: 离开
2. 事件对象产生的顺序
1). down-->move-->move-->....-->up
2). 每个事件对象产生后, 都会找到一个消费者来消费处理此事件
3. 事件相关API
1). MotionEvent: 代表对UI的操作单元的类, 它的对象在用户触摸UI时系统自动创建基对象, 并将相关的数据保存在此对象中
ACTION_DOWN=0 : down类型值ACTION_UP=1 : up类型值 ACTION_MOVE=2 : move类型值 int getAction() : 得到事件类型值
float getX() : 得到事件的X轴坐标(相对于当前View的左顶点)float getRawX() : 得到事件的X轴坐标(相对于屏幕的左顶点)float getY() : 得到事件的Y轴坐标(相对于当前View的左顶点)
float getRawY() : 得到事件的Y轴坐标(相对于屏幕的左顶点)
2). Activity
boolean dispatchTouchEvent(MotionEvent event) : 分发事件
boolean onTouchEvent(MotionEvent event) : 处理事件的回调
3). View
boolean dispatchTouchEvent(MotionEvent event): 分发事件
setOnClickListener(OnClickListener l) : 设置触摸事件监听器对象
private OnTouchListener mOnTouchListener; //触摸事件监听器对象变量
public interface OnTouchListener { //事件监听器接口
boolean onTouch(View v, MotionEvent event); // 监听器对象的回调方法
}
boolean onTouchEvent(MotionEvent event) : 事件监听回调方法
setOnclickListener(OnclickListener listener) : 设置点击监听器
setOnLongClickListener(OnLongClickListener listener) : 设置长按事件监听器
4). ViewGroup
boolean dispatchTouchEvent(MotionEvent ev) : 重写View的此方法, 如果当前ViewGroup不拦截, 会分发给对应的子View处理事件
boolean onInterceptTouchEvent(MotionEvent ev) : 拦截触摸事件, 返回值如果为true表示拦截,后面的事件就会交给当前View来处理, 默认为false
requestDisallowInterceptTouchEvent(boolean disallowIntercept) : 如果参数为true, 使当前View及其外层的所有父View不能拦截后面的事件
4. View的事件处理
1). Touch事件的方法执行顺序:
①. dispatchTouchEvent()
②. setOnTouchListener的onTouch()
③. onTouchEvent()
2). 执行的详细过程
①. 在dispatchTouchEvent()会判断是否设置了Touch监听器?
如果没有直接进入②
如果有, 调用监听器的onTouch()方法, 如果onTouch方法返回true到此结束, 如果返回false进入②
②. 调用onTouchEvent()
在down时, send一个延时500ms的消息准备触发长按事件监听回调)
如果0.5s内在产生了up事件, 此时就会移除长按的延时消息, 就会去执行点击事件监听回调
如果0.5内没有产生up事件, 也没有离开, 就会调用长按事件监听回调方法, 如果返回的值是true就不可能再触发点击监听回调了, 否则还会触发.
3). 说明:
①. 如果view的onTouch()(监听器回调)或onTouchEvent(监听回调)在down时返回true, 那第一个move事件就会交给当前View处理,
否则后面的所有事件都不会到达此View了
②. 如是move事件处理返回true, 下一个move/up事件就会交给当前View处理,否则就会找父View或Activity处理
③. 整体原则: 每个Event对象创建后, 最终肯定会有一个消费者: 可能是View, 也可能是ViewGroup, 实在不行就交给Activty消费处理
5. ViewGroup的事件处理
1). 相关方法执行顺序:
①. dispatchTouchEvent()
②.onInterceptTouchEvent()
③. 对应子View的dispatchTouchEvent()
2). 执行的详细过程:
①. 在dispatchTouchEvent()中, ACTION_DOWN时, 判断是否拦截,如果没有拦截,则找到包含当前x,y坐标的子View,赋值给mMotionTarget,
然后调用mMotionTarget.dispatchTouchEvent()处理down事件
②. 在dispatchTouchEvent()中, ACTION_MOVE时, 判断是否拦截,如果没有拦截,则直接调用mMotionTarget.dispatchTouchEvent(ev)
③. 在dispatchTouchEvent()中, ACTION_UP时, 判断是否拦截,如果没有拦截,则直接调用mMotionTarget.dispatchTouchEvent(ev)
④. 如果没有找到合适的子View来消费当前event, 则将自己当成View来处理event
3). 关于拦截:
①. 如何拦截?: ViewGroup中onInterceptTouchEvent()默认返回false, 也就是不拦截, 如果想拦截就重写此方法, 并返回true, 这样事件就不会分发给子View处理
②. 如何不被拦截?: 如果子View不希望父View(也就是当前ViewGroup)拦截event, 子View可以执行: getParent().requestDisallowInterceptTouchEvent(true)
------相关资料推荐
Android View 事件分发机制 源码解析
Android ViewGroup事件分发机制
Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
Android事件分发机制完全解析,带你从源码的角度彻底理解(下)