已开启
fix: 修复外部改变状态,开关动画消失;onAsyncPress 失败时会先切换 UI 再回滚[update verson to 1.1.1-beta.1] #16
fix: 修复外部改变状态,开关动画消失;onAsyncPress 失败时会先切换 UI 再回滚[update verson to 1.1.1-beta.1] #16
已开启
yesses创建于 8 天前
yesses
yesses
8 天前

变更概述

本 PR 对鸿蒙化三方库 react-native-switch-pro 质量加固问题修复与工程完善:

  • 修复外部 value 属性变更时,鸿蒙版无动画直接切换到新值(瞬时跳变)
  • 修复 onAsyncPress 失败时会先切换 UI 再回滚,产生"闪烁"效果
  • 新增 Example demo 示例工程(含 HarmonyOS harmony 目录及 testerino 演示页面)
  • 更新 README 文件为新模板,并新增英文版 README(README_en.md)

一、三方库源码修改点(重点)

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),再由 animateSwitchAnimated.timing 从当前位置动画到目标位,动画真正完成后才 setState 更新内部 value,全程无 setValue 瞬移。配套调整:

  • 删除 syncSwitchToValue(直接 setValue 瞬移)与中间实现 executeToggleToValue(先 setValue 瞬移到反侧起点再动画,自身会产生一次可见跳动),切换动画统一收敛到 animateSwitch / animateHandler,动画结构对齐上游 1.0.5
  • switchAnimation 初始值由 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 个用例:

用例 测试场景 预期
基础切换 非受控/受控开关点击 点击后 200ms 平滑动画,无回闪(防闪烁回归)
onSyncPress 同步回调 回调参数为切换后的新值(true/false 交替)
onAsyncPress 成功 点击后延迟 1s callback(true) 等待期间开关保持原位,1s 后才动画切换
onAsyncPress 失败 点击后延迟 1s callback(false) 开关保持原位,不出现回滚闪烁
外部修改 value 按钮改变 value prop 200ms 动画过渡,非瞬时跳变
width、height 自定义宽高 开关尺寸正确
circleColorActive、circleColorInactive 圆点颜色 两态颜色正确
disabled 禁用状态 点击/拖拽无响应
circleStyle 圆点自定义样式 样式生效
backgroundActive、backgroundInactive 背景颜色 两态背景色正确

三、文档修改

  • CHANGELOG.md:新增 v1.1.1-beta.1 版本记录
  • README.md:更新为新版文档模板(含简介、下载安装、Link 说明、接口文档)
  • 新增 README_en.md 英文版文档
  • 版本号 1.1.0 -> 1.1.1-beta.1(涉及 package.json / CHANGELOG.md)

四、自测说明

  • 基础切换:点击后 200ms 平滑动画,无回闪
  • onSyncPress:回调参数为切换后的新值
  • onAsyncPress 成功:点击后开关保持原位,1s 后 callback(true) 才动画切换
  • onAsyncPress 失败:callback(false) 后开关保持原位,无回滚闪烁
  • 外部修改 value:按钮改变 value prop,有 200ms 动画过渡(非瞬时跳变)
  • width/height、圆点颜色、背景颜色、circleStyle、disabled 等样式属性均正常

资料修改

  • 是否已在 README 说明该接口/功能的变化:是(README 更新为新模板,新增英文版 README_en.md)
  • 是否已在 README 和 package.json 修改了版本信息:是(版本号 1.1.0 -> 1.1.1-beta.1)

Checklist

likedislike
合并受阻
openharmony_ci
openharmony_ci成员
8 天前 评论:

感谢提交 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:

likedislike
openharmony_ciopenharmony_ci成员
8 天前 添加了label:dco检查失败
yessesyesses
8 天前 强制推送  1 个提交:81b954c1-fix: 修复外部改变状态,开关动画消失;onAsyncPress 失败时会先切换 UI 再回滚
openharmony_ci
openharmony_ci成员
8 天前 评论:

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

likedislike
openharmony_ciopenharmony_ci成员
8 天前 删除了label:dco检查失败
此处折叠了90条消息 查看更多
yesses
yesses
6 天前 评论:

【PR 描述修正】已按最终提交修正「一、源码修改点」第 1 条变更信息,PR_DESCRIPTION.md 已随本次提交(c94690e)同步更新,PR 正文同步修改:

  • 原第 1 条「修改后」引用的 executeToggleToValue 为中间实现(最终代码中该函数已删除),现修正为实际实现:外部 value 变更调用 toggleSwitchToValue(true, nextProps.value)
  • 实际修复方案:外部变更与用户点击收敛到同一条切换动画路径——先由 animateHandler 复位圆点缩放,再由 animateSwitchAnimated.timing当前位置执行 200ms 平滑动画到目标位,动画真正完成后才 setState 更新内部 value,全程无 setValue 瞬移
  • 配套调整:删除 syncSwitchToValue / executeToggleToValue(均为基于 setValue 瞬移的实现),切换动画统一收敛到 animateSwitch / animateHandler,动画结构对齐上游 1.0.5;switchAnimation 初始值 ±offset∓1,对齐 render 插值区间端点
  • example 验证用例不变:Example/src/switch-pro/index.tsx「外部修改value:通过按钮改变value prop,应有200ms动画过渡(非瞬时跳变)」
likedislike
openharmony_ciopenharmony_ci成员
6 天前 删除了label:静态检查失败
openharmony_ci
openharmony_ci成员
6 天前 评论:

代码有更新,重置PR验证状态

likedislike
openharmony_ci
openharmony_ci成员
6 天前 评论:

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

likedislike
cpf-manager
cpf-manager6 天前进行代码检视1
lib/index.js
@@ -71,0 +69,4 @@
69+ /* }, 800)
70+ /* })
71+ */
72+ this.toggleSwitchToValue(true, nextProps.value)
cpf-manager
cpf-manager6 天前评论:

【AI-Review】【严重】【基础代码问题】【代码逻辑错误】toggleSwitchToValue 延迟 setState 导致 componentWillReceiveProps 丢弃父组件的快速 value 变更

● 问题:本 PR 将 componentWillReceiveProps 中的 syncSwitchToValue(即时 setState)替换为 toggleSwitchToValue(lib/index.js:140-153)。toggleSwitchToValue 仅在 200ms animateSwitch 动画完成且 finished=true 时才执行 setState({ value: toValue })(lib/index.js:143-150),动画期间 this.state.value 仍是旧值。而 componentWillReceiveProps 的早退判断 if (nextProps.value === this.state.value) return(lib/index.js:59)依赖 this.state.value,动画期间该判断基于过期值,父组件在同一动画窗口内的第二次 value 变更会被误判为"已同步"而直接跳过。

● 触发路径:设父组件当前 value=falsestate.value=false。父组件改为 value=truecomponentWillReceiveProps 判断 nextProps.value(true) !== state.value(false)nextProps.value(true) !== this.props.value(false) 均成立,调用 toggleSwitchToValue(true, true)(lib/index.js:72)启动 200ms 动画,state.value 要等 200ms 后才更新为 true。100ms 内父组件改回 value=falsecomponentWillReceiveProps 判断 nextProps.value(false) === state.value(false) 为真,直接 return(lib/index.js:59-61),第二次变更被丢弃。200ms 后第一个动画完成,setState({ value: true }),开关停在 on,与父组件期望的 off 不一致。被替换前的 syncSwitchToValue 在调用瞬间即 setState({ value: toValue })state.value 立即更新为 true,因此第二次 componentWillReceiveProps({value:false})nextProps.value(false) !== state.value(true) 成立,会继续调用 syncSwitchToValue(false) 将开关重置为 off,不存在此回归。

● 建议:在 toggleSwitchToValue 开头先同步 setState({ value: toValue, alignItems: toValue ? 'flex-end' : 'flex-start' }),再以当前位置为起点播放 animateSwitch 动画(不调用 setValue(fromValue) 以避免此前修复的视觉跳跃),使 componentWillReceiveProps 的早退判断始终基于最新 state.value;或在 componentWillReceiveProps 中用一个独立字段(如 this.pendingValue)记录动画进行中的目标值,早退判断改为 nextProps.value === this.pendingValue,不依赖 state.value

likedislike