实战:构建多点触控指针追踪容器组件)
移动开发UI组件【免费下载链接】react-native-gesture-handlerDeclarative API exposing platform native touch and gesture system to React Native.项目地址https://gitcode.com/gh_mirrors/re/react-native-gesture-handler点击查看免费下载本指南聚焦react-native-gesture-handler手动手势教程中的 Step 3如何搭建负责承载手势逻辑并渲染全部指针指示器的容器组件。你将学会用useManualGesture初始化一个无激活条件的手势对象、用共享值Shared Value数组管理最多 10 个指针的状态并将其挂载到GestureHandlerRootView与GestureDetector之上为后续onTouchesDown/onTouchesMove/onTouchesUp回调与状态机控制打下基础。教程定位Step 3 在手动手势示例中的角色官方文档以“追踪屏幕上全部指针”为例讲解手动手势整个示例被拆分为 7 个步骤本篇文章对应 Step 3其任务描述为现在我们需要制作一个组件来处理手势并绘制所有指针指示器。我们将指针数据存储在一个数组中并在一个Animated.View内渲染它们。与之相邻的步骤分别是Step 1 定义Pointer数据类型见 step1.mdStep 2 实现展示单个指针的PointerElement组件见 step2.mdStep 47 依次补全onTouchesDown、onTouchesMove、onTouchesUp回调与onActivate/onDeactivate状态联动。Step 3 是连接“数据结构”与“手势回调”的枢纽没有它指针状态无处渲染手势对象也无处挂载。完整示例代码可在 use-manual-gesture.mdx 的Full example code折叠块中查看。Step 3 完整代码逐行拆解import { StyleSheet } from react-native; import { GestureDetector, GestureHandlerRootView, GestureStateManager, useManualGesture, } from react-native-gesture-handler; import Animated, { useAnimatedStyle, SharedValue, useSharedValue, } from react-native-reanimated; ... export default function Example() { const trackedPointers: SharedValuePointer[] []; const active useSharedValue(false); for (let i 0; i 10; i) { trackedPointers[i] useSharedValuePointer({ x: 0, y: 0, visible: false, }); } const gesture useManualGesture({}); return ( GestureHandlerRootView GestureDetector gesture{gesture} Animated.View style{{ flex: 1 }} {trackedPointers.map((pointer, index) ( PointerElement pointer{pointer} active{active} key{index} / ))} /Animated.View /GestureDetector /GestureHandlerRootView ); } const styles StyleSheet.create({ pointer: { width: 60, height: 60, borderRadius: 30, backgroundColor: red, position: absolute, marginStart: -30, marginTop: -30, }, });这段代码完成了四件关键事情下面逐一深入。1. 用共享值数组持有指针状态const trackedPointers: SharedValuePointer[] []; const active useSharedValue(false); for (let i 0; i 10; i) { trackedPointers[i] useSharedValuePointer({ x: 0, y: 0, visible: false, }); }trackedPointers是一个长度固定为 10 的SharedValuePointer数组每个元素对应一个可能的触点Pointer类型由 Step 1 定义{ x: number; y: number; visible: boolean }。数组下标即触点的id——后续onTouchesDown回调中正是通过touch.id作为索引写入对应指针的数据。之所以固定 10 个是为了覆盖移动端最多同时出现 10 个触点的典型上限避免运行期动态扩容带来的复杂性与性能抖动。useSharedValue是 react-native-reanimated 提供的跨 UI 线程/工作线程共享的可变值容器渲染层useAnimatedStyle可以在动画帧内直接读取它而无需走 React 重渲染这正是高帧率指针追踪的关键。active共享值则记录手势是否已激活供PointerElement在蓝色未激活与红色已激活之间切换。2. 初始化无配置的手势对象const gesture useManualGesture({});这是整个示例的核心。手动手势Manual Gesture在官方文档 use-manual-gesture.mdx 中被定义为一种没有特定激活条件也没有预设事件数据的普通手势。其状态必须通过状态管理器State Manager手动控制。即使所有指针都从屏幕上抬起它也不会自动失败。因此传入空对象{}即可——useManualGesture的配置参数是可选的。从源码看useManualGesture.ts 内部会先用useClonedAndRemappedConfig克隆并重映射配置再调用通用的useGesture(SingleGestureName.Manual, manualConfig)创建手势实例。整个 v3 API 的手势统一走 useGesture.ts 这一入口Manual 只是其中一种以“完全手动控制状态”为特征的手势类型。若你需要修改其他连续手势的激活条件官方文档建议查看对应手势的配置项或使用manualActivation修饰符来接管其状态管理而无需从零实现。3. 三层结构RootView → Detector → Animated.ViewGestureHandlerRootView GestureDetector gesture{gesture} Animated.View style{{ flex: 1 }} {trackedPointers.map((pointer, index) ( PointerElement pointer{pointer} active{active} key{index} / ))} /Animated.View /GestureDetector /GestureHandlerRootViewGestureHandlerRootView手势系统的根容器必须包裹整个手势处理区域通常是应用根部它是原生手势识别器得以挂载的前提GestureDetector接收gesture属性将手势对象绑定到其子视图上子视图即手势的作用范围Animated.View手势的实际承载视图同时作为 10 个PointerElement的绝对定位容器每个指示器用position: absolute定位。PointerElement是 Step 2 中定义的组件它接收pointer与active两个共享值通过useAnimatedStyle实时计算translateX/translateY/scale/backgroundColor——未激活时为蓝色圆形60×60、borderRadius: 30激活后变为红色并放大 1.3 倍visible为false时缩放为 0 从而“隐藏”指针。4. 演示用样式表const styles StyleSheet.create({ pointer: { width: 60, height: 60, borderRadius: 30, backgroundColor: red, position: absolute, marginStart: -30, marginTop: -30, }, });position: absolute配合marginStart: -30、marginTop: -30使每个 60×60 的指示器以自身中心点为基准定位translateX/translateY通过useAnimatedStyle写入后指针便能平滑跟随触点移动。注意backgroundColor在此只是初始值运行时颜色由useAnimatedStyle根据active动态覆盖。挂载之后回调如何接管指针数据Step 3 只负责搭建骨架真正的指针追踪逻辑在 Step 47 中通过useManualGesture({...})的回调补全。这些回调共享 Step 3 建立的trackedPointers与gesture作用域形成完整闭环回调触发时机作用onTouchesDown手指按下将changedTouches中每个触点的x/y写入trackedPointers[touch.id]并置visible: true若numberOfTouches 2调用GestureStateManager.activate(e.handlerTag)onTouchesMove手指移动仅更新发生移动的触点位置onTouchesUp手指抬起隐藏对应指针若numberOfTouches 0调用GestureStateManager.deactivate(e.handlerTag)onActivate/onDeactivate手势激活/结束同步active.value驱动指示器变色与缩放官方文档特别提醒示例没有处理onTouchesCancel因为这种极简场景预期不会触发取消但在真实应用中当它被调用时应当清理已取消指针大多数情况下是全部活跃指针的数据。GestureStateManager.activate与deactivate是本例状态控制的关键。从源码看gestureStateManager.ts 中二者均为worklet函数内部调用setGestureState(handlerTag, state)优先走globalThis._setGestureStateSync同步否则回退到_setGestureStateAsync异步——deactivate实际将手势置为State.ENDfail则置为State.FAILED。e.handlerTag正是由手势系统为当前手势实例分配的唯一标识用于把 JS 侧的指令路由到对应的原生手势识别器。手动手势的适用场景与边界Step 3 所构建的模式——固定容量共享值数组 空配置手势 回调自行驱动状态——适用于任何“激活条件无法用现成手势表达”的场景例如必须两根手指同时落下才激活的手势本例即如此numberOfTouches 2需要实时读取所有触点坐标以驱动自定义绘制白板、多点标注手势行为完全由业务逻辑决定而不是由库内置的判定规则决定。同时要明确边界手动手势没有预设的激活标准所有状态迁移激活、失败、结束都必须由你在回调中显式调用GestureStateManager完成它不会像Tap/Pan那样在手指全部抬起时自动结束。文档中的示例也因此无需担心“全部指针抬起后手势仍悬而未决”——因为onTouchesUp里已通过deactivate主动收尾。小结Step 3 用约 55 行代码完成了一个可运行的多点触控容器10 个共享值槽位对应最多 10 个触点useManualGesture({})创建“零预设条件”的手势对象三层视图结构把手势、渲染与状态管理串联在一起。它是整个手动手势教程的骨架章节——后续所有回调都围绕这份骨架工作最终在 use-manual-gesture.mdx 的完整示例中组装成可交互的多指追踪演示。赞分享移动开发UI组件【免费下载链接】react-native-gesture-handlerDeclarative API exposing platform native touch and gesture system to React Native.项目地址https://gitcode.com/gh_mirrors/re/react-native-gesture-handler点击查看免费下载相关推荐react-native-gesture-handler 手动手势Manual Gesture之 onTouchesUp多指抬起检测与手势状态收尾实战react native gesture handler 手动手势Manual Gesture之 onTouchesUp多指抬起检测与手势状态收尾实战 本移动开发UI组件react-native-gesture-handler 手动手势实战用 onTouchesMove 实时追踪屏幕上的全部触点react native gesture handler 手动手势实战用 onTouchesMove 实时追踪屏幕上的全部触点 本文聚焦 react nati移动开发UI组件react-native-gesture-handler 手动手势实战用 onTouchesDown 捕获触点并驱动手势激活react native gesture handler 手动手势实战用 onTouchesDown 捕获触点并驱动手势激活 本篇技术指南聚焦 react n移动开发UI组件上一篇Jinjava企业级Java模板引擎终极指南下一篇ProxyPin请求重写企业级网络调试的终极解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考