事件分发机制

基本概述

需要关注下是View还是ViewGroup,但整体上是一致的。

事件分发机制主要解决的核心问题是,将Touch事件,传递对应的view消费

  • 如何传递
  • 传递给谁

我们学习事件分发机制解决什么问题:

  • 如何利用机制去拦截目标事件
  • 如何利用机制去处理事件冲突

整体原则

  • 传递时,从外向内、从父到子
  • 消费时,从内向外、从子到父

三座大山

整个机制三个关键函数

  • dispatchTouchEvent, 事件传递
    • 返回true,表明事件已经消费,会终止事件向下(由父向子)传递,结束
    • 返回false,表明事件未被消费,将会回传给父View的onTouchEvent
    • 调用super.dispatchTouchEvent,继续下传
  • onInterceptTouchEvent
    • 这个方法只存在于 ViewGroup 中
    • 返回true,表明要拦截事件,会回调onTouchEvent
    • 返回false,表明不做拦截,后面会继续下传
  • onTouchEvent, 事件消费
    • 返回true,表明事件被消费,结束
    • 返回false,表明事件没有被消费,将会继续回传父view
    • 调用super.onTouchEvent,继续往上回传

事件分发路径图

在默认的实现下,事件流向是一个U型图。

需要注意的是,

关键点

一般情况下,有以下事件:

  1. ACTION_DOWN
  2. ACTION_MOVE
  3. ACTION_UP
  4. ACTION_CANCEL

KEY 1

而我们说的一个事件就是指上面的某一个,但若说一个完整事件序列,则是从down--move--...--cancel/up这样一个所有一个操作周期所发生的所有事件。

KEY 2

不同的事件的分发路径其实是有所差别的。

一旦前面的事件确定了接收的view,那么分发的U形图就会"向上收缩"。 例如下图被ViewGroup2接收后,后续事件在默认情况下,如红线只会走到VG2然后被处理,蓝色区域不会走了。

KEY 3

CANCEL事件会稍微特殊一点,发生在后续事件被其他view拦截的时候,原来接收事件的view就会收到CANCEL事件。

例如,Down事件被下层消费之后,后续的Move、Up事件是有可能会被上层拦截的这也正是常常发生事件冲突的地方。

若被拦截,则原本应该消费的View会收到cancel事件。

滑动冲突的处理方式

滑动冲突是非常常见的,通常发生在多个可滑动的布局嵌套的场景,例如RecyclerView{ ScrollView }, RecyclerView{ ListView }, ViewPager{ RecyclerView }

典型的,根据两个控件的滑动方向,可以将滑动冲突分成两类:一个是不同方向的滑动冲突 ,如外层控件垂直滑动,内层控件水平滑动。另一个就是同方向的滑动冲突,如内外两层控件都是垂直滑动。

拦截方法有两种,本质也是万变不离其宗(改变分发的路线):

  • 外部拦截法
  • 内部拦截法

在一些特殊业务场景下,可能需要内外一起完成配合来实现特殊的效果。

(1)外部拦截法

在外层ViewGroup中的onInterceptTouchEvent中,对move事件进行精细化控制。

例如在外部是纵向、内部是横向的滚动场景时,我们判断dy>dx时【实际条件根据业务场景设置】选择拦截即在onInterceptTouchEvent中return true.

(2)内部拦截法

在内部ViewGroup中的dispatchTouchEvent或onTouchEvent方法中,调用api requestDisallowInterceptTouchEvent(true)来阻止父布局拦截后续事件。

这时候内部ViewGroup是不会回调onInterceptTouchEvent的,所以需要在dispatchTouchEvent或onTouchEvent方法中调用。

例如在外部是纵向、内部是横向的滚动场景时,我们判断dx>dy时【实际条件根据业务场景设置】

设置requestDisallowInterceptTouchEvent(true)

做滑动布局,应该在哪拦截事件?

首先滑动布局是ViewGroup类型,里面存在子View。

1)明确一点,滑动事件肯定是在ViewGroup层去拦截;

2)滑动事件拦截,不应该以Down为起点,而应该是MOVE。否则:子View的点击事件也会被拦截

3)Move事件应该在onInterceptTouchEvent中拦截

你可参考

juejin.cn/post/716844...

相关推荐
于慨1 天前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz1 天前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
从前慢丶1 天前
前端交互规范(Web 端)
前端
CHU7290351 天前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing1 天前
Page-agent MCP结构
前端·人工智能
王霸天1 天前
💥别再抄网上的Scale缩放代码了!50行源码教你写一个永不翻车的大屏适配
前端·vue.js·数据可视化
小领航1 天前
用 Three.js + Vue 3 打造炫酷的 3D 行政地图可视化组件
前端·github
@大迁世界1 天前
2026年React大洗牌:React Hooks 将迎来重大升级
前端·javascript·react.js·前端框架·ecmascript
PieroPc1 天前
一个功能强大的 Web 端标签设计和打印工具,支持服务器端直接打印到局域网打印机。Fastapi + html
前端·html·fastapi
悟空瞎说1 天前
深入 Vue3 响应式:为什么有的要加.value,有的不用?从设计到源码彻底讲透
前端·vue.js