
本文记录把react-native-step-indicator步骤条 / 进度指示器适配到 HarmonyOS 的完整过程。这是一个纯 JS 组件库源码475 行功能是横向或纵向的步骤条带可点击的步骤、可自定义的标签渲染以及一条随进度增长的已完成色带。它不需要任何原生接线。它有两个很适合做量化验证的特点我把它们都做成了硬判据已完成色带的宽度可以直接算出来constanimateToPosition(progressBarSize/(stepCount-1))*position;// progressBarSize width * (stepCount - 1) / stepCount// ⇒ 绿条宽度 width * k / N当前步骤的圆圈更大默认 40 vs 30且底色是白色而其它步骤是实心绿 / 浅绿 ⇒白圆的圆心 x 就是currentPosition的位置圆心 x width/(2N) k * width/N styles.stepContainer 是 flex:1 ⇒ 等分实测容器宽 1248px、N5三个实例全部精确命中实例k绿条宽度预言 / 实测当前步圆心 x预言 / 实测当前步圆尺寸S100 /无绿条✓160.8 /161✓120pxS22499.2 /499✓660.0 /660✓120pxS34998.4 /998满格✓1159.2 /1159✓120px设备侧断言13 / 13 全部通过一次构建就过。一、先说结论项结果上游最新版1.0.3license: MIT上游 star1459库类型纯 JS 单组件库StepIndicator步骤条是否需要原生适配不需要无harmony/、无NativeModulesimport 图只有react/react-native/./types运行时依赖零dependencies未声明peerDependencies只有react/react-nativeprepare⚠️保留了上游的prepare: bob buildbob是 devDependency⇒目录/file:接入必须--ignore-scriptsmainlib/commonjs/index编译产物⇒ 必须单独核对产物导出形态只有default一个导出且它是React.memo(...)返回的对象typeof object、无可用prototype需要 HAR / 权限 / ohpm❌ 都不需要设备侧断言✅13 / 13 全部通过A 5 B 7 C 1★ 两个像素判据✅ 绿条宽度 W·k/N、当前步圆心 W/(2N)k·W/N——三个实例全部逐像素吻合★ 当前步更大更白✅ 当前步圆120px40vp其余90px30vp★ 交互✅ 点步骤圆 ⇒onPress(0)触发且 index 正确二、判定与接入步做法结果①package.json里有没有harmony.autolinking没有②仓库里有没有harmony/没有③代码里有没有NativeModules/requireNativeComponent全无④import 图体检防env那类坑只有react/react-native/./types✓npminstallgithttps://atomgit.com/oh-react-native/react-native-step-indicator.git#1.0.3-ohos-1.0.0--ignore-scripts// metro.config.jswatchFolders:[path.resolve(__dirname,../react-native-step-indicator)],importStepIndicatorTestAppfrom./StepIndicatorTestApp;AppRegistry.registerComponent(StepIndicatorTestApp,()StepIndicatorTestApp);hdc shell aa force-stop com.rnoh084.demo hdc shell aa start-bcom.rnoh084.demo-aEntryAbility--psrnAppKey StepIndicatorTestApp不需要HAR、权限、ohpm、link-harmony。三、读源码取到的真值src/index.tsx475 行3.1 组件形态与默认值const StepIndicator ({ currentPosition 0, stepCount 5, direction horizontal, customStyles: customStylesFromProps defaultStyles, labels [], onPress, renderStepIndicator: renderCustomStepIndicator, renderLabel, }: StepIndicatorProps) { … }; export default React.memo(StepIndicator);要点函数组件 参数解构默认值⇒React 19 下没问题不是defaultProps那类坑默认导出是React.memo(...)的返回值⇒typeof object、没有可用的prototype实测模块运行时只有default一个导出Object.keys(...) [default]customStyles会与defaultStyles合并{...defaultStyles, ...customStylesFromProps}。3.2 ★ 进度条的几何与公式// 背景条浅绿 progressBarBackgroundStyle { backgroundColor: customStyles.separatorUnFinishedColor, // #a4d4a5 position: absolute, top: (height - separatorStrokeWidth) / 2, left: width / (2 * stepCount), right: width / (2 * stepCount), height: separatorStrokeWidth, // 默认 2vp }; // ⇒ progressBarSize width * (N-1) / N // 已完成条绿同样的 left/right但宽度受动画控制 progressBarStyle { …, width: progressAnim }; // 动画目标 const animateToPosition (progressBarSize / (stepCount - 1)) * position; Animated.timing(progressAnim, { toValue: animateToPosition, duration: 200, useNativeDriver: false });⇒绿条宽度 width · k / NuseNativeDriver: false⇒ JS 驱动。3.3 ★ 当前步骤为什么更大更白const getStepStatus (p) p currentPosition ? CURRENT : p currentPosition ? FINISHED : UNFINISHED; // CURRENT白底 粗绿边 sizeAnim动画到 currentStepIndicatorSize40 // FINISHED实心 stepIndicatorFinishedColor #4aae4f尺寸 stepIndicatorSize30 // UNFINISHEDstepIndicatorUnFinishedColor #a4d4a5尺寸 30 // 且 stepContainer 是 flex:1 ⇒ 每步等分 ⇒ 圆心 x width/(2N) k*width/N默认配色正是像素判据的依据用途颜色当前步底色#ffffff白已完成步 / 已完成条#4aae4f绿未完成步 / 背景条#a4d4a5浅绿3.4 交互const stepPressed (position) { if (onPress) { onPress(position); } }; // 每个步骤与标签都包在 TouchableWithoutFeedback 里点击 ⇒ stepPressed(position)⚠️注意源码里还有一个onCurrentPositionChanged但它是组件内部的const函数src/index.tsx:389不是 propsrc/types.ts里也没有声明它⇒它无法从外部监听见第六节我的失误。四、验证设计两个独立的像素判据判据内容为什么可靠① 绿条宽度已完成色带#4aae4f的宽度应为W·k/N与动画跑到哪直接挂钩② 当前步圆心白色圆圈#ffffff40vp的圆心 x 应为W/(2N)k·W/N且尺寸比其它大位置 尺寸双重特征不易误判两个判据互相独立一个看色带长度、一个看圆圈位置能交叉验证。测量方式以布局 dump 的绝对坐标为准见第七节的教训截图有 JPEG 色晕几何量不准。五、实测结果5.1 断言 13 / 13组内容结果A 契约默认导出存在、是 memo 对象、typeof object、有$$typeof、无可用prototype、枚举全部具名导出5/5B 渲染与几何4 个实例渲染未抛错、标题不与状态栏重合、4 个实例尺寸、两个判据的预言值7/7C 回调事件记录格式1/1合计13/13实例尺寸{s1:416x79,s2:416x79,s3:416x79,s4:416x79}⇒容器宽 416vp 1248px✓5.2 ★★ 几何逐像素复核布局 dump 绝对坐标S2k2 / N5y2034..2043 (h9) x161..1159 (w998) ← 背景条浅绿 y2034..2043 (h9) x161..660 (w499) ← ★ 已完成条绿 y1978..2098 (h120) x600..720 (w120) ← ★ 当前步k240vp圆心 660 y1993..2083 (h90) x116..206 / 366..456 / 865..955 / 1114..1204 ← 其余 30vp圆心 161/411/910/1159S3k4 / N5y711..720 (h9) x161..1159 (w998) ← ★ 已完成条【满格】 圆心161 / 411 / 660 / 910 / ★1159当前步 120px其余 90pxS1k0只有背景条浅绿没有已完成绿条✓汇总实例绿条宽度 预言实测当前步圆心 预言实测当前步尺寸S1 (k0)00无✓160.8161✓120pxS2 (k2)499.2499✓660.0660✓120pxS3 (k4)998.4998✓1159.21159✓120px⇒两个判据、三个实例、六组数字全部逐像素吻合✓✓5.3 ★ 交互实测S4 是 3 步stepCount3的受控实例圆心预言为361248/6k·416⇒244 / 660 / 1076实测圆: x199..289 w90 圆心 x244 ✓ 圆: x615..705 w90 圆心 x660 ✓ 圆: x1016..1136 w120 圆心 x1076 ✓当前步更大点击第 1 个圆244, 1680⇒ 日志PRESS onPress(0)⇒onPress触发且 index 正确0 基✓5.4 UI标题不与状态栏重合TITLE measureInWindow y420 状态栏高 117 ⇒ 420 117不重合 ✓六、我自己的一个失误我把onCurrentPositionChanged当成了回调 prop在测试页里这样写StepIndicator currentPosition{pos} onPress{...} onCurrentPositionChanged{(p) logEvent(POS-CHANGED onCurrentPositionChanged(${p}))} // ← 无效 /实测结果点击只打出PRESS onPress(0)没有任何POS-CHANGED。读源码后确认onCurrentPositionChanged是组件内部定义的const函数src/index.tsx:389在getStepStatus之后由内部的useEffect([currentPosition, progressBarSize])调用它不在 props 解构里src/types.ts的StepIndicatorProps里也没有它⇒它不是对外 API外部无法监听。纠正把 C 组的设计改为只断言真实存在的 proponPress并在文章里写明onCurrentPositionChanged不是 prop。⚠️教训回调名不等于回调 prop。看到组件内部有个onXxx(...)调用就去props解构里核一遍——只有当它出现在解构参数或propTypes/类型声明里才是对外 API。七、方法上的一个教训几何量必须用 dump不能信截图本轮我先用截图扫色来量进度条得到的是x117..1203而布局 dump给出的绝对坐标是x161..1159。差异来自JPEG 压缩的色晕边缘像素被混色落到我的颜色容差之外/之内。dump 的数值是精确的161 与预言 160.8 只差 0.2px。⇒判据分工几何位置/尺寸⇒ 用布局 dump 的绝对坐标颜色/状态/视觉对照 ⇒ 用截图比如绿条到哪结束这种颜色跳变dump 里没有颜色信息。八、已知限制与本次验证边界8.1 用这个库要知道的事项说明prepare: bob build仍在目录/file:接入必须加--ignore-scripts否则会因为找不到bob而安装失败main指向编译产物lib/commonjs/index源码在src/⇒ 核对改动时要连产物一起比默认导出是memo对象typeof object、import后拿不到prototypeonCurrentPositionChanged不是 prop它是内部函数外部无法监听要感知变化只能靠自己的currentPosition状态进度条是动画的200msuseNativeDriver: falseJS 驱动截图时机太早可能拍到中间态当前步比其它步大currentStepIndicatorSize(40) vsstepIndicatorSize(30) ⇒ 布局高度按 40 算8.2 本次验证的边界只验证了directionhorizontal默认⇒directionvertical完全未测源码里竖屏分支用的是height/(2*stepCount)/top/bottom几何另有公式renderLabel/renderStepIndicator两个自定义渲染回调未验证customStyles自定义未逐项验证只用了默认配色labels的选中态颜色未做像素核对源码里currentStepLabelColorvslabelColor不同但文字颜色不好扫步骤数 ≠ 5 的横向几何只验了stepCount3S4其它数量未穷举进度条动画的中间态未验证只在动画结束后测量stepCount1的边界未测源码里progressBarSize/(stepCount-1)会除以 0⇒animateToPosition Infinity然后被isNaN兜住 ⇒ 但这只是代码级推断未实测只在一台模拟器上验证Pura X Viewdensity 31320×2232没有真机未做跨平台对照。未改动库代码。九、常见问题Q1为什么import StepIndicator from react-native-step-indicator拿不到prototype因为它导出的是React.memo(StepIndicator)的返回值是个对象typeof object不是 class/函数。要看它的 props 请查src/types.ts的StepIndicatorProps。Q2npm install报找不到bob因为包里保留了prepare: bob build而bobreact-native-builder-bob只是 devDependency。目录/file:接入时prepare会执行⇒ 安装失败。解法npminstall../react-native-step-indicator --ignore-scripts走.tgz安装不会触发prepare。Q3进度条已完成色带的长度是怎么算的绿条宽度 width * currentPosition / stepCount推导背景条从left/right width/(2N)起 ⇒ 自身宽width*(N-1)/N动画目标是(progressBarSize/(stepCount-1)) * position⇒ 乘起来正好是width*k/N。实测W1248, N5k2 ⇒499px算 499.2、k4 ⇒998px算 998.4✓Q4怎么把当前步骤做得更显眼默认已经做了两件事当前步圆更大currentStepIndicatorSize40 vsstepIndicatorSize30、底色变白stepIndicatorCurrentColor: #ffffff且带粗绿边currentStepStrokeWidth: 5。都能通过customStyles改。Q5onCurrentPositionChanged怎么监听监听不了—— 它是组件内部的函数不是 propStepIndicatorProps里没有它。要感知位置变化请自己持有currentPosition状态const [pos, setPos] useState(0); StepIndicator currentPosition{pos} onPress{setPos} / // 位置变化由你自己掌握Q6点击步骤能拿到下标吗能。onPress(position)给的就是0 基下标实测点第 1 个圆得到onPress(0)。Q7stepCount传 1 会怎样按源码推progressBarSize / (stepCount - 1)会除以 0⇒ 目标值变成Infinity/NaN而代码里有isNaN(animateToPosition) ? 0 : animateToPosition兜底 ⇒ 进度条宽度会退回 0。⚠️这一条属代码级推断本轮未实测。Q8颜色怎么改统一走customStylesStepIndicator customStyles{{ stepIndicatorFinishedColor: #4aae4f, stepIndicatorUnFinishedColor: #a4d4a5, stepIndicatorCurrentColor: #ffffff, separatorFinishedColor: #4aae4f, separatorUnFinishedColor: #a4d4a5, currentStepLabelColor: #4aae4f, }} /Q9这个库需要鸿蒙侧做什么特殊处理吗不需要。纯 JS、零依赖、import 图干净只有react/react-native、不需要 HAR / 权限 /ohpm。唯一要注意的是安装时的prepare和上面几条 API 细节。小结react-native-step-indicator是纯 JS 单组件库源码 475 行零依赖、无需原生接线。设备侧13 / 13断言通过一次构建就过。最值得记下来的是这几条★★ 能从源码推出确定的像素值时就把它当判据。这个库的进度条宽度有闭式公式W·k/N当前步的圆心也有W/(2N)k·W/N⇒ 我据此做了两个互相独立的判据三个实例六组数字全部逐像素吻合499/998 与 660/1159。⇒比看起来对硬得多而且一旦公式写错会立刻暴露。★ 几何量必须用布局 dump 的绝对坐标不要信截图。我用截图扫色量出117..1203而 dump 是161..1159—— 差的正是JPEG 色晕。⇒分工几何用 dump颜色/视觉用截图。★ 回调名 ≠ 回调 prop。onCurrentPositionChanged名字看着像回调 prop实际是组件内部的const函数⇒ 我从外部传它完全没有效果。⇒判断一个回调是否对外要去props解构 /propTypes/ 类型声明里核一遍这与引用一个子路径/可选入口前先看它的 import 图是同一个思路只是发生在 API 层面。prepare是跨库反复出现的坑。这个库保留了上游的prepare: bob build⇒ 目录/file:接入会失败。⇒接库时把scripts扫一遍prepare/prepublish/postinstall一律用--ignore-scripts兜底。main指向编译产物时要连产物一起核。本库main lib/commonjs/index所以逐文件比对里必须包含lib/**—— 否则源码没改不能推出跑起来的产物没改。本篇用到的库项内容三方库react-native-step-indicator上游1.0.3的鸿蒙适配版适配仓库https://atomgit.com/oh-react-native/react-native-step-indicator适配 TAG1.0.3-ohos-1.0.0需要 HAR / 权限 / ohpm都不需要纯 JS零依赖库类型纯 JS 单组件库步骤条 / 进度指示器运行时依赖零peerDependencies只有react/react-nativeprepare⚠️ 有prepare: bob build⇒目录/file:接入必须--ignore-scripts许可证MIT上游仓库https://github.com/24ark/react-native-step-indicator★1459宿主工程RNOH084Demo测试页rnAppKey StepIndicatorTestApp# 从适配仓库安装npminstallgithttps://atomgit.com/oh-react-native/react-native-step-indicator.git#1.0.3-ohos-1.0.0--ignore-scripts# 本地目录接入开发常用—— prepare: bob build 会让不带 --ignore-scripts 的安装失败npminstall../react-native-step-indicator --ignore-scripts// metro.config.jswatchFolders:[path.resolve(__dirname,../react-native-step-indicator)],import StepIndicator from react-native-step-indicator; const [pos, setPos] useState(0); const labels [已下单, 已付款, 已发货, 运输中, 已签收]; // ① 基本用法横向5 步 StepIndicator currentPosition{pos} stepCount{5} labels{labels} onPress{setPos} // ★ 真 prop点击步骤/标签会给 0 基下标 / // ② 自定义配色 StepIndicator currentPosition{2} stepCount{5} customStyles{{ stepIndicatorFinishedColor: #4aae4f, stepIndicatorUnFinishedColor: #a4d4a5, stepIndicatorCurrentColor: #ffffff, separatorFinishedColor: #4aae4f, separatorUnFinishedColor: #a4d4a5, currentStepLabelColor: #4aae4f, }} / // ③ 自定义标签渲染 StepIndicator currentPosition{1} stepCount{3} labels{[A, B, C]} renderLabel{({position, stepStatus, label, currentPosition}) ( Text{${position}:${label}(${stepStatus})}/Text )} / // ⚠️ onCurrentPositionChanged 不是 prop内部函数传了也没用# 换页启动测试页force-stop 不能省换页参数只在冷启动生效hdc shell aa force-stop com.rnoh084.demo hdc shell aa start-bcom.rnoh084.demo-aEntryAbility--psrnAppKey StepIndicatorTestApp几何判据的复现方式# ★ 几何量用布局 dump 的【绝对坐标】不要用截图扫色JPEG 色晕会让边缘偏几十像素devecocli ui layout|Select-StringMARK-S2# 期望W1248, N5, k2# 背景条 x161..1159 (w998) 已完成绿条 x161..660 (w499)# 当前步圆 w120 圆心 x660 其余圆 w90 圆心 x161/411/910/1159验证环境项版本React Native0.84.1React19.2.3RNOHnpm / ohpmreact-native-oh/react-native-harmony/rnoh/react-native-openharmony0.84.3Node.js / npmv24.14.0/11.9.0DevEco Studio26.0.0.621HarmonyOS SDKAPI 2626.0.0.32设备HarmonyOS 7.0.0(26.0.0) Beta2 模拟器Pura X Viewohos-x641320×2232density 3本机状态栏高度117px页面留白取 48vp宿主 HAP 产物entry-default-signed.hap本次构建assembleHap3 分 41 秒一轮就过无重编验证规模设备侧13 / 13断言几何复核3 个实例 × 2 个判据 6 组绿条 0/499/998、圆心 161/660/1159、当前步圆 120px交互 1 次onPress(0)UI 安全区 1 项相关社区与项目地址项目地址React Native 鸿蒙官方社区CPF-RNhttps://atomgit.com/CPF-RNRNOH 框架仓库https://atomgit.com/openharmony-RN/ohos_react_nativeRNOH 三方库使用文档https://atomgit.com/OpenHarmony-RN/usage-docsReact Native for OpenHarmony 组织https://atomgit.com/oh-react-nativeRN 三方库鸿蒙适配清单https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview欢迎加入 CPF-RN 鸿蒙社区https://atomgit.com/CPF-RNReact Native for OpenHarmony 组织https://atomgit.com/oh-react-nativeRN 三方库鸿蒙适配清单https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview