事件分发机制

基本概述

需要关注下是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...

相关推荐
蝙蝠编人生8 小时前
TailwindCSS vs UnoCSS 性能深度对决:究竟快多少
前端
ZXH01228 小时前
浏览器兼容性问题处理
前端
鹏多多9 小时前
flutter-切换状态显示不同组件10种实现方案全解析
android·前端·ios
向葭奔赴♡9 小时前
HTML的本质——网页的“骨架”
前端·javascript·html
小岛前端9 小时前
Vue3 键盘快捷键的高效开发!
前端·vue.js·开源
江城开朗的豌豆9 小时前
小程序避坑指南:这些兼容性问题你遇到了几个?
前端·javascript·微信小程序
云浪9 小时前
说透 Suspense 组件的实现原理
前端·javascript·vue.js
我有一棵树9 小时前
浏览器/用户代理默认样式、any-link 伪类选择器
前端·css·html
江城开朗的豌豆9 小时前
玩转小程序页面跳转:我的路由实战笔记
前端·javascript·微信小程序