☰
react-native-gesture-handler 2.0 升级指南:从 Handler 组件迁移到 Gesture API 与 GestureDetector
2026/10/8 7:57:56 网站建设 项目流程
  • 移动开发
  • UI组件

【免费下载链接】react-native-gesture-handler

Declarative 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 官方 2.x 版本文档《Upgrading to the new API introduced in Gesture Handler 2》为主体,结合仓库中packages/react-native-gesture-handler/src的真实源码,系统讲解从 1.x 组件式 API 迁移到 2.x Gesture API 的完整路径:先解决 Android 上RNGestureHandlerEnabledRootView的历史包袱,再掌握Gesture对象、GestureDetector组件、新回调模型(onBegin/onStart/onUpdate/onChange/onEnd/onFinalize)、链式配置手势,以及用组合 API 替换嵌套 Handler 与waitFor/simultaneousHandlers的全部方法。读完本文,你可以把旧式<TapGestureHandler>、<PanGestureHandler>等组件代码平稳改写为声明式、可组合的新 API。

一、迁移前置条件:先脱离RNGestureHandlerEnabledRootView(仅 Android)

Gesture Handler 1.x 要求通过重写createRootView返回RNGestureHandlerEnabledRootView实例,才能让手势系统在 Android 上工作。该类的实现方式一直是许多难以定位、难以修复的崩溃(hard-to-debug and hard-to-fix crashes)的源头,因此在2.0 中被标记为废弃(deprecated),并在2.4 中被彻底移除。如果项目里还在使用它,请先完成迁移:

  • 详细迁移步骤见仓库文档 migrating-off-rnghenabledroot 指南。
  • 迁移完成后,Android 上不再需要任何自定义 RootView 包装,GestureHandlerRootView即可承载新 API(详见仓库文档 root-view.mdx 与组件实现 GestureHandlerRootView.android.tsx)。

只有先完成这一步,升级到新 API 才有干净的基座。

二、新 API 概览:Gesture对象 +GestureDetector组件

2.x 最核心的变化,是引入新的 Gesture API以及配套的GestureDetector组件。旧式 API 为每种手势单独提供组件(TapGestureHandler、PanGestureHandler、PinchGestureHandler……),而新 API 则通过一个GestureDetector组件,把“手势配置对象”挂接到它包裹的视图上,大量样板代码被库内部消化掉。

配置对象由Gesture对象创建,例如:

const tapGesture = Gesture.Tap().onStart(() => { console.log('Tap!'); }); ... return ( <GestureDetector gesture={tapGesture}> <View /> </GestureDetector> );

从源码看,Gesture.Tap()实际返回一个TapGesture实例(见 gestureObjects.ts),它继承自BaseGesture;每个实例会分配唯一的gestureId,并维护自己的config与handlers(见 gesture.ts)。GestureDetector在挂载/更新时通过 attachHandlers.ts、updateHandlers.ts 等模块把配置下发到原生侧,这是“省去大量样板代码”的底层来源。

提示:仓库主分支源码已将Gesture构建器 API 标记为@deprecated,建议逐步迁移到新的 hook 式 API(如useTapGesture,见 gestureObjects.ts 的注释)。但 2.x 版本文档所对应的升级路径依然以Gesture对象为核心,且其回调与配置语义与 hook API 一致,掌握本节即可平滑衔接后续演进。

三、告别onGestureEvent与onHandlerStateChange:新的回调模型

新 API 中不再有onGestureEvent和onHandlerStateChange这两个回调。状态机由库在底层自动驱动,开发者只需为“特定状态迁移或事件”注册对应回调。手势状态常量定义在 State.ts:

UNDETERMINED: 0, FAILED: 1, BEGAN: 2, CANCELLED: 3, ACTIVE: 4, END: 5

新回调与状态迁移的对应关系如下:

回调触发时机
onBegin手势进入BEGAN状态。大多数情况下,即手指首次触碰到视图、手势开始处理触摸流的时候
onStart手势满足激活条件,从BEGAN迁移到ACTIVE状态
onUpdate替代onGestureEvent,在手势处于ACTIVE状态期间,每次收到新事件时触发
onChange若已定义,则在onUpdate之后立即触发;事件数据与onUpdate相同,但额外携带change字段,表示自上一个事件以来的变化量(例如Pan手势会额外携带changeX、changeY)
onEnd手势从ACTIVE迁移到END、FAILED或CANCELLED三者之一。回调的第二个参数(success)用于区分手势是因用户操作完成,还是因其他原因(被系统取消、满足失败条件)而结束
onFinalize手势进入END、FAILED或CANCELLED状态时触发;如果手势此前处于ACTIVE,则onEnd会先被调用(同样可用第二个参数判断结束原因)

onEnd与onFinalize的核心区别:onEnd仅在手势曾处于ACTIVE状态时才调用;onFinalize只要手势进入过BEGAN就会被调用。因此,推荐用onEnd清理onStart中建立的资源,用onFinalize清理onBegin(或同时清理onBegin与onStart)中建立的资源。

在源码层面对应关系清晰可查:BaseGesture中定义了onBegin/onStart/onEnd/onFinalize(见 gesture.ts),ContinousBaseGesture定义了onUpdate/onChange/manualActivation(见 gesture.ts)。所有回调都会在注册时通过isWorklet(callback)检测是否为 Reanimated worklet,并记录到handlers.isWorklet数组中——如果安装了react-native-reanimated且回调均为 worklet,则默认在 UI 线程执行;也可用.runOnJS(true)强制切回 JS 线程(见 gesture.ts)。

以Pan手势为例,onChange的changeX/changeY由changeEventCalculator计算:首次事件取当前translationX/translationY,之后取与上一次事件的差值(见 panGesture.ts),这就是“变化量”语义的实现来源。

四、链式配置手势:从 Props 到 Builder 方法

新 API 采用builder 链式模式配置手势。每个手势提供与旧 Props 同名(或高度相似)的方法来完成定制,方法调用返回手势自身,可连续链式书写。

旧式写法:

return ( <TapGestureHandler numberOfTaps={2} maxDurationMs={500} maxDelayMs={500} maxDist={10} onHandlerStateChange={({ nativeEvent }) => { if (nativeEvent.state === State.ACTIVE) { console.log('Tap!'); } }}> <View /> </TapGestureHandler> );

新 API 写法效果完全相同:

const tapGesture = Gesture.Tap() .numberOfTaps(2) .maxDuration(500) .maxDelay(500) .maxDistance(10) .onStart(() => { console.log('Tap!'); }); return ( <GestureDetector gesture={tapGesture}> <View /> </GestureDetector> );

结合 tapGesture.ts 的源码,上述方法的底层配置项与默认值如下:

链式方法底层 config 字段默认值含义
.numberOfTaps(count)numberOfTaps1激活手势所需的最少点按次数
.maxDistance(maxDist)maxDist无一次点按中手指允许移动的最大距离(点)
.maxDuration(duration)maxDurationMs500手指按下后必须在该毫秒数内抬起
.maxDelay(delay)maxDelayMs500多点点按时,两次点按之间允许的最大间隔(毫秒)
.minPointers(minPointers)minPointers1激活前必须放下的最少手指数
.maxDeltaX(delta)/.maxDeltaY(delta)maxDeltaX/maxDeltaY无单轴方向允许的最大位移(点)

注意新旧方法名的差异:旧 propmaxDurationMs对应方法.maxDuration(...),maxDelayMs对应.maxDelay(...),maxDist对应.maxDistance(...)。其他手势的可用修饰符,可查阅仓库文档中的 Gestures 章节(如 use-pan-gesture.mdx、use-tap-gesture.mdx);例如Pan手势额外提供activeOffsetX/Y、failOffsetX/Y、minDistance、minVelocity、averageTouches等,且activeOffsetX/Y支持传入区间数组[start, end](见 panGesture.ts)。

五、同一视图挂多个手势:用组合 API 替代嵌套 Handler

使用旧式 Handler 组件时,若要在同一视图上识别多种手势,只能把组件层层堆叠;若要叠加动画,还得在每个 Handler 之间插入Animated.View,最终形成很深的组件树:

return ( <TapGestureHandler ... > <Animated.View> <PanGestureHandler ... > <Animated.View> <PinchGestureHandler ... > <YourView /> </PinchGestureHandler> </Animated.View> </PanGestureHandler> </Animated.View> </TapGestureHandler> );

使用GestureDetector后,可以借助Gesture Composition API(详见 gesture-composition 文档)把多个手势组合到同一视图上:

const tapGesture = Gesture.Tap(); const panGesture = Gesture.Pan(); const pinchGesture = Gesture.Pinch(); return ( <GestureDetector gesture={Gesture.Race(tapGesture, panGesture, pinchGesture)}> <YourView /> </GestureDetector> );

组合 API 提供三种基本组合,对应旧式堆叠的不同语义:

  • Gesture.Race(...):ComposedGesture,第一个激活的手势会取消其余手势。从源码看,Race只是把各手势放进一个普通组合,不额外建立同时或等待关系(见 gestureObjects.ts)。
  • Gesture.Simultaneous(...):SimultaneousGesture,用于替代“应当能同时识别”的堆叠 Handler。其prepare()会为每个手势构造“除自己之外的所有手势”列表并写入simultaneousWith关系,且不会让手势与自己同时(见 gestureComposition.ts)。
  • Gesture.Exclusive(...):ExclusiveGesture,用于替代“要求其他手势失败才能识别”的堆叠 Handler。其prepare()按传入顺序建立链式requireToFail关系——越靠前的手势优先级越高,后面的手势需要等待前面的手势全部失败(见 gestureComposition.ts)。典型例子:Exclusive(doubleTap, singleTap)可同时支持双击与单击。

源码细节:组合手势在prepare()阶段会把关系写入各子手势的config.simultaneousWith/config.requireToFail,并基于relationsSnapshot重建,避免重复渲染时关系引用不断累积导致内存泄漏(见 gestureComposition.ts 的注释,涉及 issue #3763、#4238)。

六、替换waitFor与simultaneousHandlers:跨视图手势关系

组合 API 解决的是同一视图上多个手势的关系。如果需要建立不同视图上手势之间的关系,或需要让新手势与旧式 Handler 组件建立关系,则应使用以下方法:

  • simultaneousWithExternalGesture(...gestures):替代旧 propsimultaneousHandlers,允许多个组件上的手势同时识别。
  • requireExternalGestureToFail(...gestures):替代旧 propwaitFor,延迟当前手势的激活,直到传入的手势全部失败(或根本不开始)。
  • withRef(refObject):当需要把 ref 对象传给旧式 Handler 组件(用于旧 API 互操作)时,用.withRef(ref)把它挂到手势对象上。

三者均为链式方法,可一次传入多个手势(见 gesture.ts):

const panGesture = Gesture.Pan().withRef(panRef); const pinchGesture = Gesture.Pinch(); const longPressGesture = Gesture.LongPress() .requireExternalGestureToFail(pinchGesture) .simultaneousWithExternalGesture(panGesture);

源码确认:simultaneousWithExternalGesture/requireExternalGestureToFail/blocksExternalGesture内部通过addDependency把目标手势追加进config.simultaneousWith/config.requireToFail/config.blocksHandlers数组(见 gesture.ts);而withRef会把 ref 写入config.ref,并在手势initialize()时把ref.current指向手势实例,从而与旧 API 的 ref 体系对接(见 gesture.ts 与 gesture.ts)。

七、迁移清单与后续路径

综合全文,从 1.x 升级到 2.x 的完整动作可归纳为:

  1. Android:确认已移除RNGestureHandlerEnabledRootView(详见 migrating-off-rnghenabledroot),必要时用GestureHandlerRootView替代。
  2. 组件 → 对象:把<XxxGestureHandler>组件替换为Gesture.Xxx()配置对象 +<GestureDetector gesture={...}>。
  3. 回调 → 状态迁移:把onGestureEvent改写为onUpdate,把onHandlerStateChange中对State.ACTIVE、State.END等的手工判断,改写为onStart、onEnd、onFinalize等语义化回调;需要增量数据时追加onChange。
  4. 嵌套 → 组合:同视图多手势用Gesture.Race/Gesture.Simultaneous/Gesture.Exclusive;跨视图关系用simultaneousWithExternalGesture/requireExternalGestureToFail,并用withRef兼容旧 Handler ref。
  5. 当前主线展望:仓库主分支已将Gesture构建器、ComposedGesture等标记为弃用,推荐向 hook 式 API(useTapGesture、usePanGesture、useSimultaneousGestures等)演进(见 gestureObjects.ts)。2.x 升级文档中的回调语义、配置字段与组合关系模型在 hook API 中保持一致,可平滑迁移。

相关实现与文档入口汇总:

  • 手势基类与回调:gesture.ts
  • 组合实现:gestureComposition.ts
  • 手势工厂:gestureObjects.ts
  • 状态常量:State.ts
  • 组合 API 完整文档:gesture-composition.md
  • 官方测试用例(验证GestureDetector组合行为):api_v3.test.tsx、RelationsTraversal.test.tsx
  • 移动开发
  • UI组件

【免费下载链接】react-native-gesture-handler

Declarative API exposing platform native touch and gesture system to React Native.

项目地址:https://gitcode.com/gh_mirrors/re/react-native-gesture-handler
点击查看免费下载
上一篇:Apache DolphinScheduler 全面解析:分布式可视化 DAG 工作流调度平台入门指南
下一篇:mGBA模拟器完全指南:从新手到高手的7个实用技巧

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询