从Click理解移动端App开发

当前移动端App开发分为Native(原生)开发和Hybrid(混合)开发;

现在通过移动端App的点击事件来进行探究:

HTML

对于通过HTML构建的网页,Click作为一个事件本身与其他事件相同是浏览器窗口中发生、特定交互瞬间,成为js与DOM之间交互的桥梁;

事件流从window开始到具体的DOM tree(Document Object Model Tree)的顶层节点进行事件的捕获,在节点确定目标后再通过冒泡回溯document.addEventListener(event, function, useCapture),若不使用document.stopPropagation()进行事件拦截就会导致某事件会触发parent层级的相应事件。

微信小程序的事件机制与HTML类似。

React Native

在RN中有很多View组件,只要实现了正确的Responder方法,就可以成为触摸事件的响应者;

View.props.onStartShouldSetResponder: (evt) => true,在用户开始触摸的时候(手指刚刚接触屏幕的瞬间),是否愿意成为响应者?

View.props.onMoveShouldSetResponder: (evt) => true,如果 View 不是响应者,那么在每一个触摸点开始移动(没有停下也没有离开屏幕)时再询问一次:是否愿意响应触摸交互呢?

View.props.onResponderGrant: (evt) => {} - View,现在要开始响应触摸事件了。这也是需要做高亮的时候,使用户知道他到底点到了哪里;

View.props.onResponderReject: (evt) => {},响应者现在"另有其人"而且暂时不会"放权",请另作安排;

onStartShouldSetResponder与onMoveShouldSetResponder是以冒泡的形式调用的,即嵌套最深的节点最先调用;

这意味着当多个 View 同时在ShouldSetResponder中返回 true 时,最底层的 View 将优先"夺权";
但是有些时候,某个parent View 会希望能先成为响应者;
我们可以利用"捕获期"来解决这一需求;
响应系统在从最底层的组件开始冒泡之前,会首先执行一个"捕获期",在此期间会触发on
ShouldSetResponderCapture系列事件;

因此,如果某个parent View 想要在触摸操作开始时阻止child组件成为响应者,那就应该处理onStartShouldSetResponderCapture事件并返回 true 值;

View.props.onStartShouldSetResponderCapture: (evt) => true;

View.props.onMoveShouldSetResponderCapture: (evt) => true。

Flutter

Flutter有自己的Engine,这导致Flutter在各平台上都能很好的兼容;

Flutter Engine是基于Dart Runtime环境(UI、GPU、I/O线程,还有原生Platfrom线程),Dart Runtime会首先创建和启动DartVM虚拟机,DartIsolate会初始化并启动一个DartIsolate,启动流程的最后会执行main(),执行runApp(),获得WidgetsBinding单例对象;

其中GestureBinding负责手势处理,提供了window.onPointerDataPacket回调,绑定Framework手势子系统,是Framework事件模型与底层事件的绑定入口;

Flutter内部的组件是tree型结构,handlePointerEvent处理具体手势,通过调用GestureBinding._handlePointerEventImmediately实现,这个方法是为了进行命中测试找到可以处理事件的组件;

发起命中测试RendererBinding.hitTest(parent组件的hitTest中会调用child组件的hitTest,所以若child组件通过命中测试将会添加在parent组件前)将可以被响应的RenderObject对象添加进队列保存下来;

接下来进行事件分发GestureBinding.dispatchEvent,内部是顺序执行handleEvent;

最终保证了最顶层的通过命中测试的组件去执行对应的event。

iOS

继承了UIResponser的对象:UIApplication、UIWindow、UIViewController、UIView、UIButton、UILabel;

通过UITouch方法处理和传递UIEvent;

open func touchesBegan(_ touches: Set, with event: UIEvent?);

open func touchesMoved(_ touches: Set, with event: UIEvent?);

open func touchesEnded(_ touches: Set, with event: UIEvent?);

open func touchesCancelled(_ touches: Set, with event: UIEvent?);

当屏幕收到触摸信号,此时拥有的信息是触摸点的坐标,需要找到第一响应者来响应触摸;

系统将点击事件加入到UIApplication管理的消息队列里;

UIApplication会从消息队列中取出该事件传递给UIWindow;

在UIWindow中调用方法hitTest:withEvent:,在方法中调用pointInside:withEvent:来判断触摸点的坐标是否在UIWindow内部;

若返回YES,则倒序遍历子视图找到最终响应的子UIResponer;

若最终返回一个UIResponer,那么最终响应UIResponer并结束事件传递,如果无值返回则将UIWindow作为响应者。

Android

安卓的触摸事件(MotionEvent)也有一套响应链,层级是通过Activity到ViewGroup到View;

dispatchTouchEvent()负责将事件分发给子视图或自己处理;

onInterceptTouchEvent()只在ViewGroup中才有,用于拦截事件,决定是否传递给子视图;

onTouchEvent()负责处理事件,返回true表示消费了事件,false则相反。

当前移动端App使用的事件传递使用的是一套类似的链式结构,这与屏幕组件是tree型结构相关。

相关推荐
●VON4 小时前
Flutter 鸿蒙插件适配实战:用 device_screen_brightness 2.0.0 控制并监听屏幕亮度
flutter·华为·harmonyos
天空之城--6 小时前
Android逆向安全合规接单指南
android·安全
星辰徐哥8 小时前
本地视频预览别只自己看:把Remotion动效项目发给客户远程验收
docker·ai·node.js·html·音视频·react·remotion
消失的旧时光-19438 小时前
Android 系统层扫盲 09:AMS、ATMS、WMS、PMS 到底分别管什么?
android·wms·pms·ams·aosp·atms
Godikov8 小时前
Android 系统级设备应用踩坑实录:sharedUserId 签名、SDK 授权失败 -4、开机自启与 U 盘 OTA 升级
android
IT毕设实战小研11 小时前
基于大数据的国内主要农作物产量趋势分析与可视化
android·java·大数据·django·课程设计
风早爽太12 小时前
Flutter 开发笔记:share_plus 分享插件
笔记·flutter
●VON13 小时前
Flutter 鸿蒙插件适配实战:用 boot_time_plugin 1.0.0 读取启动时间与运行时长
flutter·华为·harmonyos
企业数字化笔记13 小时前
固定资产历史数据怎么导入系统?Excel模板、字段映射和数据校验
android·java·数据库·后端
龙之叶13 小时前
Android出海系列-GMS认证介绍
android