当前Pull Request已关闭, 关闭人@dingchengjie
感谢提交 Pull Requests !此PR未通过DCO校验。
校验失败可能原因:
1. 未签署“DCO协议”(开发者原创声明协议),在线签署、查看签署状态。
2. Commits 中未包含 Signed-off-by信息,参考FAQ处理。
修复上述问题后,在PR的评论框输入“check dco” ,单击”评论”,系统将再次进行DCO校验。
当前检测到如下Commits 未包含Signed-off-by信息:
Thanks for submitting a pull request. This pull request has not passed the DCO check.
Possible causes:
1. You have not signed the Developer Certificate of Origin (DCO). Sign the DCO and check DCO status.
2. The commits do not contain the Signed-off-by information. To resolve this issue, see FAQs.
After resolving the preceding issues, enter check dco in the comment box of this pull request and click Comment. The system will check DCO status again.
The following commits do not contain the Signed-off-by information:


感谢提交 Pull Requests!
Thanks for submitting a pull request.


感谢提交 Pull Requests!
Thanks for submitting a pull request.


【AI-Review】【一般】【基础代码问题】【代码逻辑错误】_onPanResponderMove 与 _onPanResponderRelease 读取的 value 不一致,动画飞行中拖拽会导致开关卡在中间位或反向切换
● 问题:_onPanResponderRelease(lib/index.js:118)已改为读取 this._pendingValue 作为动画飞行中的有效当前值,但 _onPanResponderMove(lib/index.js:100)仍直接读取 this.state.value。由于 executeToggleToValue(lib/index.js:154-185)把 setState({value}) 推迟到动画完成后才执行,动画飞行中 state.value 仍是旧值,_pendingValue 才是新目标,两个手势回调读取的"当前值"不一致。
触发路径:用户第一次点击(state.value=false,executeToggleToValue(true) 启动,_pendingValue=true,switchAnimation 1->19 动画启动)-> 200ms 动画期间用户再次触摸并拖拽 -> _onPanResponderGrant(lib/index.js:91-97)调用 animateHandler(this.handlerSize * SCALE),animateHandler 内部 handlerAnimation.stopAnimation() 通过 Animated.parallel 默认的 stopTogether=true 中断整个 parallel,switchAnimation 停在中间值(例如 10)-> _onPanResponderMove 读取 state.value=false(旧值),计算 toggleable = false ? ... : (gestureState.dx > -10);若用户向右拖(dx=15),toggleable = (15 > -10) = true -> _onPanResponderRelease 读取 _pendingValue=true,targetValue = !true = false,executeToggleToValue(false),开关切到与用户拖拽方向相反的 false。若用户向左拖(dx=-15),toggleable = (-15 > -10) = false -> 走 else 分支(lib/index.js:146-148)只调用 animateHandler(this.handlerSize),不重启 switchAnimation,开关圆点卡在 1->19 的中间位(例如 10)。
● 影响:一般。仅在 200ms 动画飞行中再触摸并拖拽时触发,但一旦触发会出现圆点卡在中间位或反向切换的可见缺陷,与 PR "防闪烁/快速连点" 的目标相悖。
● 建议:_onPanResponderMove 与 _onPanResponderRelease 使用同一有效值来源。_onPanResponderMove(lib/index.js:100)改为 const value = this._pendingValue !== undefined ? this._pendingValue : this.state.value,使 toggleable 与 release 的 targetValue = !value 基准一致;另外 _onPanResponderRelease 的 else 分支(toggleable=false)在 _pendingValue !== undefined 时应调用 executeToggleToValue(this._pendingValue) 恢复飞行中被打断的动画,避免圆点卡在中间位。


【AI-Review】【一般】【基础代码问题】【代码逻辑错误】handlerAnimation 仍在动画但 render 不再使用,按压放大反馈丢失且产生无效动画
● 问题:render(lib/index.js:277)把内层 Animated.View 的 width 从 handlerAnimation 改为常量 this.handlerSize,但 executeToggleToValue(lib/index.js:156、164-167)和 animateHandler(lib/index.js:188、190-193)仍在 this.state.handlerAnimation 上调用 stopAnimation() 和 Animated.timing(...)。_onPanResponderGrant(lib/index.js:96)调用 animateHandler(this.handlerSize * SCALE) 想放大圆点提供按压反馈,但 handlerAnimation 已不参与任何样式属性(render 中无任何地方引用 handlerAnimation),Animated.timing 产生的动画值无人消费。
触发路径:用户按下 -> _onPanResponderGrant -> animateHandler(this.handlerSize * SCALE) -> handlerAnimation 从 handlerSize(19) 动画到 handlerSize*6/5(22.8),但 render 中 width: this.handlerSize(19)是常量,圆点尺寸不变,按压放大反馈完全丢失。同样,executeToggleToValue 中 Animated.timing(this.state.handlerAnimation, {toValue: this.handlerSize, ...}) 也是无人消费的无效动画。
● 影响:一般。原库的按压放大反馈(圆点按下时放大 1.2 倍)在 RNOH 上完全消失,用户按下无任何尺寸反馈;同时 Animated.timing(handlerAnimation, ...) 仍在每帧驱动一个无人读取的 Animated.Value,属于无效计算(stopAnimation() 的副作用用于打断 parallel 是有意义的,但 Animated.timing 部分本身是冗余的)。
● 建议:若按压放大反馈是有意移除,应一并删除 handlerAnimation 状态、animateHandler 函数及 executeToggleToValue 中对 handlerAnimation 的 Animated.timing(保留 switchAnimation.stopAnimation() 用于打断),改为单独 Animated.timing(switchAnimation).start(...);若按压反馈需要保留,可使用非布局属性驱动放大,例如 transform: [{ scale: handlerAnimation.interpolate({ inputRange: [this.handlerSize, this.handlerSize * SCALE], outputRange: [1, 1.2] }) }],避免逐帧 JS 驱动 width 布局属性引发 RNOH 闪烁。


变更概述
本 PR 对鸿蒙化三方库 react-native-switch-pro 质量加固问题修复与工程完善:
value属性变更时,鸿蒙版无动画直接切换到新值(瞬时跳变)onAsyncPress失败时会先切换 UI 再回滚,产生"闪烁"效果一、三方库源码修改点(重点)
1. 修复外部
value属性变更时无动画直接切换根因:
componentWillReceiveProps中检测到外部value变更时调用syncSwitchToValue,该函数直接通过switchAnimation.setValue()将动画值瞬间设到目标位置(±offset),不经过Animated.timing,因此开关状态被外部改变时 UI 无动画直接跳变到新值。修改前——
syncSwitchToValue直接 setValue,无动画过渡:if (typeof nextProps.value !== 'undefined' && nextProps.value !== this.props.value) { this.syncSwitchToValue(nextProps.value) }修改后——外部变更与用户点击收敛到同一条切换动画路径
toggleSwitchToValue,从当前位置 200ms 平滑动画到目标位:if (typeof nextProps.value !== 'undefined' && nextProps.value !== this.props.value) { this.toggleSwitchToValue(true, nextProps.value) }toggleSwitchToValue先复位圆点缩放(animateHandler),再由animateSwitch以Animated.timing从当前位置动画到目标位,动画真正完成后才setState更新内部value,全程无setValue瞬移。配套调整:syncSwitchToValue(直接setValue瞬移)与中间实现executeToggleToValue(先setValue瞬移到反侧起点再动画,自身会产生一次可见跳动),切换动画统一收敛到animateSwitch/animateHandler,动画结构对齐上游 1.0.5switchAnimation初始值由value ? this.offset : -this.offset调整为value ? -1 : 1,对齐 render 插值区间端点,切换动画从边界起全程可见animateHandler(this.handlerSize * SCALE))再延时切换,按需启用example 验证:
Example/src/switch-pro/index.tsx「外部修改value:通过按钮改变value prop,应有200ms动画过渡(非瞬时跳变)」用例。2. 修复
onAsyncPress失败时先切换 UI 再回滚产生的"闪烁"根因:异步模式下点击开关时先乐观执行
executeToggleToValue(targetValue)立即切换 UI;业务侧回调result === false时再执行executeToggleToValue(value)切回原状态。两次 200ms 动画来回切换,视觉上产生"闪烁"。且调用方无法实现"等待业务确认后再切换"的等待模式。修改前——乐观切换 + 失败回滚,两次动画闪烁:
} else if (onAsyncPress) { this.executeToggleToValue(targetValue) onAsyncPress((result) => { if (!result) { this.executeToggleToValue(value) } }) }修改后——将
toggleSwitch传入回调,由调用方通过callback(true/false)决定是否切换:} else if (onAsyncPress) { const targetValue = result ? !value : this.state.value if (targetValue === this.state.value){ callback(targetValue) return } this.toggleSwitchToValue(result, !value, () => callback(targetValue)) }callback(true):执行一次切换动画(executeToggleToValue)callback(false):仅复位圆点缩放(animateHandler),开关保持原位,不产生回滚onAsyncPress = (callback) => {callback(true)},未传回调时行为与同步切换一致,无兼容性影响example 验证:
Example/src/switch-pro/index.tsx「onAsyncPress成功:点击后开关不动,1s后callback(true)才动画切换(等待模式)」「onAsyncPress失败:callback(false)后开关保持不动,不出现回滚闪烁」两个用例。二、example 测试用例
重构 Example 工程:删除旧版 android/ios 示例,新增基于 RNOH 的 harmony 工程与 testerino 演示页面(
Example/src/switch-pro/index.tsx),共 10 个用例:callback(true)callback(false)valueprop三、文档修改
四、自测说明
callback(true)才动画切换callback(false)后开关保持原位,无回滚闪烁valueprop,有 200ms 动画过渡(非瞬时跳变)资料修改
Checklist