View的触摸事件机制

温故而知新,系统整理一下。

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事件分发机制完全解析,带你从源码的角度彻底理解(下)

android触摸事件处理流程
Android应用层View绘制流程与源码分析

Android View刷新机制

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容