当前位置: 首页 > news >正文

android的事件分发机制

参考文章:图解 Android 事件分发机制

这个文章很早我就看过了,但是只是知道是这个流程,具体怎么操作,点击事件如何传递依然有点迷,甚至连这个流程图是否正确都不敢持肯定态度,所以今天就来用代码实现下,毕竟眼见为实嘛。

debug过程太繁琐这里就不一步步贴了,直接上带注释的结果

1、点击viewgroup时,事件分发流程:
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { super } ==》viewgroup.onTouchEvent { super } ==》viewgroup.setOnClickListener

2、点击view时,事件分发流程:
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { super } ==》viewgroup.onInterceptTouchEvent { super } ==》 view.dispatchTouchEvent { super } ==》view.onTouchEvent { super } ==》view.setOnClickListener

3、activity的dispatchTouchEvent返回true或者false时,事件分发流程:
activity.dispatchTouchEvent { true/false } ==》无

4、viewgroup的dispatchTouchEvent返回true时,事件分发流程:
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { true } ==》无

5、viewgroup的dispatchTouchEvent返回false时,事件分发流程:
activity.dispatchTouchEvent { super } ==》activity.onTouchEvent { super } ==》无

6、viewgroup的onInterceptTouchEvent返回true时,事件分发流程:
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { super } ==》viewgroup.onInterceptTouchEvent { true } ==》 viewgroup.onTouchEvent { super } ==》viewgroup.setOnClickListener

7、viewgroup的onInterceptTouchEvent返回false时,事件分发流程:(和super一样)
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { super } ==》viewgroup.onInterceptTouchEvent { false } ==》 view.dispatchTouchEvent { super } ==》view.onTouchEvent { super } ==》view.setOnClickListener

8、view的dispatchTouchEvent返回true时,事件分发流程:
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { super } ==》viewgroup.onInterceptTouchEvent { super } ==》 view.dispatchTouchEvent { true } ==》无

9、view的dispatchTouchEvent返回false时,事件分发流程:
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { super } ==》viewgroup.onTouchEvent { super } ==》viewgroup.setOnClickListener

10、view的onTouchEvent返回true时,事件分发流程:
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { super } ==》viewgroup.onInterceptTouchEvent { super } ==》 view.dispatchTouchEvent { super } ==》view.onTouchEvent { true } ==》无

11、view的onTouchEvent返回false时,事件分发流程:
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { super } ==》viewgroup.onTouchEvent { super } ==》viewgroup.setOnClickListener

12、viewgroup的onTouchEvent返回true时,事件分发流程:
activity.dispatchTouchEvent { super } ==》viewgroup.dispatchTouchEvent { super } ==》viewgroup.onTouchEvent { true } ==》无

13、viewgroup的onTouchEvent返回false时,事件分发流程:
activity.dispatchTouchEvent { super } ==》activity.onTouchEvent { super } ==》无

14、activity的onTouchEvent返回true或者false时,事件分发流程:
activity.onTouchEvent { true/false } ==》无

super.dispatchTouchEvent也是返回true、false,为什么和直接设置 dispatchTouchEvent{ true、false }效果完全不一样呢?这个消费是什么意思?

dispatchTouchEvent 返回 true 只代表"这次 MotionEvent 被消费了",但它不等于点击事件(onClick)一定发生。这两件事在源码里是分开的。

  • true:事件被消费,不再向父级回传,本次调用直接结束

  • false:事件没被消费,上交父 ViewGroup 的 onTouchEvent

  • super.dispatchTouchEvent():走默认分发逻辑(拦截判断 → 遍历子 View → 自身 onTouchEvent)

  • super.dispatchTouchEvent()返回 true 是因为内部的 onTouchEvent 返回了 true(或者子 View 消费了)。整个事件序列走完了完整的 U 型链路

viewgroup的onInterceptTouchEvent是不是有点多余
  • 当 ViewGroup 通过onInterceptTouchEvent返回 true 拦截事件时,原先正在处理事件的子 View 会收到一个ACTION_CANCEL,告诉它"事件序列被抢走了,请你重置状态"。
  • 如果你直接在dispatchTouchEvent里 return true,系统不会自动给子 View 补发 CANCEL。子 View 会永远卡在"按下"状态——按钮高亮清不掉、RecyclerView 的滚动状态无法复位。
  • dispatchTouchEvent方法有有一整套分发遍历流程,如果直接设置就需要手动配置这些逻辑,所以onInterceptTouchEvent才会被抽出单独来管是否拦截
具体到代码上如何设置拦截
  • 外部拦截法(父主导):父在onInterceptTouchEvent的 MOVE 中根据滑动方向决定拦截
  • 内部拦截法(子主导):子在dispatchTouchEvent里根据业务逻辑调用requestDisallowInterceptTouchEvent,调用后,父 ViewGroup 的onInterceptTouchEvent在后续 MOVE/UP 中会被跳过

/** * 事件分发测试 * activity层 */ public class MainActivity extends AppCompatActivity { private LinearlayoutViewGroup mViewGroup; private TextViewView mView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mViewGroup = findViewById(R.id.mViewGroup); mView = findViewById(R.id.mView); mViewGroup.setOnClickListener(v -> { Log.e("点击", "ViewGroup点击事件触发"); }); mView.setOnClickListener(v -> { Log.e("点击", "View点击事件触发"); }); } /** * event 普通点击会触发三次,ACTION_DOWN、ACTION_MOVE、ACTION_UP * 这里只讨论 ACTION_UP 的传递流程 * return super 默认方法 点击viewgroup和view时,传递到viewgroup 的 dispatchTouchEvent 方法 * return true/false 事件到这里结束 */ @Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == 1) Log.e("点击", "activity-dispatchTouchEvent"); return super.dispatchTouchEvent(event); } /** * return super/true/false activity的点击事件触发,事件到这里结束 */ @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == 1) Log.e("点击", "activity-onTouchEvent"); return super.onTouchEvent(event); } }
/** * viewGroup层 */ public class LinearlayoutViewGroup extends LinearLayout { public LinearlayoutViewGroup(Context context) { super(context); } public LinearlayoutViewGroup(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public LinearlayoutViewGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public LinearlayoutViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } /** * return super 默认方法,点击viewgroup时,传递给自己的 onTouchEvent 方法。点击view时,传递给自己的 dispatchTouchEvent 方法 * return true 事件到这里结束 * return false 事件传递给acivity的 onTouchEvent 方法 */ @Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == 1) Log.e("点击", "ViewGroup-dispatchTouchEvent"); return super.dispatchTouchEvent(event); } /** * 判断是否拦截了某个事件 * return super/false 默认方法,点击view时,传递到view的 dispatchTouchEvent 方法 * return true 事件传递给自己的 onTouchEvent 方法 */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (event.getAction() == 1) Log.e("点击", "ViewGroup-onInterceptTouchEvent"); return super.onInterceptTouchEvent(event); } /** * return super 默认方法,点击viewgroup时,触发viewgroup的 setOnClickListener 方法 * return true 事件到这里结束 * return false 事件传递到activity的 onTouchEvent 方法 */ @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == 1) Log.e("点击", "ViewGroup-onTouchEvent"); return super.onTouchEvent(event); } }
/** * view层 */ //@SuppressLint("AppCompatCustomView") public class TextViewView extends View { public TextViewView(Context context) { super(context); } public TextViewView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public TextViewView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public TextViewView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } /** * return super 默认方法,点击view时,传递给自己的 onTouchEvent 方法。 * return true 事件到这里结束 * return false 事件传递给viewgroup的 onTouchEvent 方法 */ @Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() == 1) Log.e("点击", "View-dispatchTouchEvent"); return super.dispatchTouchEvent(event); } /** * return super 默认方法,点击view时,触发view的 setOnClickListener 方法 * return true 事件到这里结束 * return false 事件传递给viewgroup的 onTouchEvent 方法 */ @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == 1) Log.e("点击", "View-onTouchEvent"); return super.onTouchEvent(event); } }
http://www.cnnetsun.cn/news/3626456.html

相关文章:

  • 品牌出海发稿哪家靠谱?深度拆解朝闻通全链路服务
  • AlienFX Tools终极指南:告别臃肿AWCC,打造轻量级Alienware控制中心
  • MCU基础
  • 系统架构设计师考试:高效备考策略与资源推荐
  • 如何快速选择最佳行情服务器:mootdx智能连接优化指南
  • 深度解析TI ADS8353/7853 ADC评估套件:从硬件设计到性能测试实战
  • 在windows10里的apache2.4加php8.2的环境下上安装Laravel10框架
  • 5分钟掌握PPT悬浮计时器:告别演讲超时的智能解决方案
  • 如何实现毫秒级歌词同步:Listen1跨平台音乐播放器的完整技术解析
  • CTF流量分析神器:5分钟掌握CTF-NetA终极指南
  • 抖音视频下载终极指南:douyin-downloader批量去水印工具完全教程
  • ELF文件与库的原理
  • 【20年ML系统老兵手记】:为什么你训出的模型一部署就崩?训练/推理数据流、内存模型、精度路径的3维撕裂分析
  • (99页PPT)全量系统业务战略架构图模板(附下载方式)
  • ADS8353/ADS7853评估套件实战:从硬件配置到软件分析的高精度ADC性能验证
  • 从状态码、请求头到 TLS 指纹的合规排查方法 TLSFOWARD抓包工具
  • 为什么你的vLLM部署比别人慢3.7倍?——2024主流推理框架(vLLM、TGI、Ollama、LightLLM)吞吐量与首token延迟全对比
  • 【信号去噪】基于小波阈值实现心电信号去噪附matlab代码
  • AMD Ryzen SDT调试工具:30分钟从新手到性能调优专家的终极指南
  • 2026外出客户拜访整理录音,怎么选合适的手机录音转文字助手
  • 高性能抖音批量下载系统:基于双重策略的自动化内容采集框架
  • MSP430F22x2/F22x4超低功耗MCU实战:从架构解析到传感器系统设计
  • GetQzonehistory:三步永久保存你的QQ空间数字记忆
  • 题解:Edge Reverse
  • 2026年主流YOLO模型横评与工程实践指南
  • 如何实现一站式音乐聚合播放:Listen1跨平台音乐播放器技术揭秘 [特殊字符]
  • Kimi LeetCode 3677. 统计二进制回文数字的数目 Rust实现
  • 《绝区零》3.0版本卡池流水分析:多平台数据对比与运营策略
  • 中兴光猫解锁终极指南:3步免费开启高级权限
  • 2026年AI Agent平台OpenClaw架构解析与实战测评