
灯光模拟HarmonyOS应用实战-96-float.json定义了50fp页面却继续硬编码字号用TypographyTokenAudit清理死资源与异常层级资源文件里已经有page_text_font_size50fp页面却没有任何地方引用它Index.ets仍散落着 54 次数字型fontSize()从 11 到 25 共 13 种取值。此时把所有字号机械替换成现有资源并不会完成资源化反而会让标题、辅助文字、按钮与倒计时全部变成 50fp直接破坏信息层级。当前源码能够确认的是“一条未使用的 float 资源”和“一组硬编码字号”同时存在。它们可能源于模板残留也可能是尚未完成的迁移没有设计稿、真机截图和无障碍字号实测不能断言当前每个字号都错误。正确的第一步是建立语义角色再用TypographyTokenAudit同时拦截未使用资源、未知引用和新增裸数字。本文以 Header、统计卡、题目、按钮和倒计时为例把 13 个数值归并成可解释的字号阶梯并保留需要视觉验收的边界。建议资源和脚本尚未写入The_kemusan原工程。一、先量出当前事实一条孤立资源与54次裸字号entry/src/main/resources/base/element/float.json当前只有一个条目{float:[{name:page_text_font_size,value:50fp}]}在entry/src/main中搜索page_text_font_size只有定义本身没有$r(app.float.page_text_font_size)引用。另一方面Index.ets的数字字号分布为11 两次、12 六次、13 十四次、14 六次、15 五次、16 九次、17 一次、18 三次、19 两次、20 一次、22 两次、24 两次、25 一次共 54 次。这个统计不等于“必须保留 13 级”。相邻数值可能来自细调也可能承担不同语义要先回到组件角色再决定合并。50fp 也不能因为存在于资源文件就被视为设计标准。二、资源化的单位应是语义不是数字如果只把fontSize(13)改名为font_13代码仍然要求读者记住数字用途。更可维护的 token 应表达角色语义角色当前候选值典型位置调整时要保护什么text_caption12fp统计卡标签小字号可读性text_supporting13fp副标题、标签长文本与省略text_body15fp提示与正文基础阅读舒适度text_action16fp操作按钮点击目标内层级text_option17fp判断题选项选项识别text_title19fp卡片标题与正文区分text_emphasis22fp倒计时、重点数值不压过页面主标题text_hero24fp题目与主提示长题干换行text_page_title25fp顶部标题单行省略与系统字号这是一份迁移候选不是已确认的视觉规范。相邻值合并后是否仍保持层级要结合页面截图、字体缩放与不同宽度验证。三、先建立完整的 float 资源阶梯建议资源文件保留完整回退并移除或正式迁移孤立的page_text_font_size{float:[{name:text_caption,value:12fp},{name:text_supporting,value:13fp},{name:text_body,value:15fp},{name:text_action,value:16fp},{name:text_option,value:17fp},{name:text_title,value:19fp},{name:text_emphasis,value:22fp},{name:text_hero,value:24fp},{name:text_page_title,value:25fp}]}华为资源文档说明应用资源通过$r(app.type.name)引用float 资源可以直接传给fontSize()。$r返回资源对象资源所有权和限定词目录仍由工程结构决定。华为资源分类与访问四、ArkUI 调用点要按组件角色迁移同一个 Header 中标题和副标题应明确使用不同 tokenBuilder Header() { Row() { Column() { Text(this.pageTitle) .fontSize($r(app.float.text_page_title)) .fontWeight(FontWeight.Bold) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) Text(this.getHeaderSubtitle()) .fontSize($r(app.float.text_supporting)) .maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }) } .constraintSize({ minWidth: 0 }) } }迁移时不要只替换fontSize()。字号变大后maxLines、容器最小宽度、行高和省略策略共同决定是否溢出。当前 Header 已有单行省略与minWidth: 0这些约束应保留并纳入回归。五、题目、反馈和按钮不能共用一个“正文字号”题目是当前任务焦点反馈是结果状态按钮是动作入口。它们都包含文字却不应被一个text_body吞并Text(this.getDisplayQuestionTitle()) .fontSize($r(app.float.text_hero)) .lineHeight(34) Text(this.answerMessage) .fontSize($r(app.float.text_body)) Text(${option.key}. ${option.text}) .fontSize($r(app.float.text_option)) Text(重新开始) .fontSize($r(app.float.text_action))lineHeight(34)也是数字是否需要进一步资源化取决于团队是否要统一排版节奏。本文只治理字号避免一次改动同时重构所有间距、圆角和高度但验证时必须观察行高与字号组合防止字形上下被截断。六、TypographyTokenAudit 同时检查定义与使用只扫描 ArkTS 裸数字会漏掉未使用资源只扫描资源引用又会允许新代码继续写fontSize(13)。审计结果需要双向比较exportinterfaceTypographyUsage{file:string;line:number;tokenName:string;rawNumber?:number;}exportinterfaceTypographyAuditReport{declaredTokens:string[];referencedTokens:string[];unusedTokens:string[];missingTokens:string[];rawFontSizes:TypographyUsage[];}exportfunctiondifference(left:string[],right:string[]):string[]{returnleft.filter((item)right.indexOf(item)0);}unusedTokens declared - referencedmissingTokens referenced - declared。裸字号记录文件和行号但不自动替换因为13可能是副标题、徽标或状态说明语义需要组件上下文才能决定。七、迁移清单要按组件登记不按全局替换可以先建立一个临时迁移清单每条明确组件、旧值、目标 token 和验收场景exportinterfaceTypographyMigrationItem{component:string;role:string;oldSize:number;targetToken:string;scenarios:string[];}exportconstTYPOGRAPHY_MIGRATION:TypographyMigrationItem[][{component:Header,role:pageTitle,oldSize:25,targetToken:text_page_title,scenarios:[longTitle,largeFont]},{component:ModuleCard,role:title,oldSize:19,targetToken:text_title,scenarios:[twoLineSubtitle]},{component:CommandPanel,role:prompt,oldSize:24,targetToken:text_hero,scenarios:[longCommand,smallWidth]},{component:AnswerOption,role:option,oldSize:17,targetToken:text_option,scenarios:[longOption,largeFont]}];清单是迁移工具不应长期成为第二套设计系统。完成后token 定义和组件引用才是来源清单只作为变更回执保留。八、系统字号放大时要验证容器不只看文本fp会参与字体相关的适配用户提高系统字号后固定高度与单行约束可能先暴露问题。当前页面中有固定height(50)的判断题按钮、height(86)的灯光操作卡和height(64)的倒计时圆形区。字号资源化不会自动让这些容器增长。建议把验证拆成三层文本层标题、选项、反馈能否完整阅读省略是否符合信息优先级。容器层固定高度内是否裁切按钮点击区域是否稳定。页面层小窗口、长中文、系统大字号组合下能否滚动到全部内容。这三层都需要运行时证据。源码扫描只能指出需要观察的调用点不能替代截图、无障碍服务和真实触控。九、验证矩阵要覆盖未使用、缺失与视觉回归编号输入或场景期望结果证据T96-01当前未迁移源码报告裸字号与孤立page_text_font_size静态报告T96-02引用不存在 token阻止提交missingTokensT96-03声明后无引用提示移除或登记保留理由unusedTokensT96-04Header 长标题主标题单行省略副标题不挤出返回按钮页面截图T96-05四行长题干能滚动阅读不裁切选项交互记录T96-06系统大字号固定高度组件无严重截断目标设备截图T96-07深色资源限定词字号引用仍可解析构建与运行日志T96-08新增fontSize(14)审计阻止裸数字回流自动化输出静态门禁应有少量允许项例如第三方组件或确实只在一次性实验中使用的值允许项需要文件、行、原因和到期条件不能用全局关闭绕过。十、常见迁移问题与排查顺序现象先看什么常见原因修复方式改了 float.json页面毫无变化$r引用资源从未被使用按组件迁移调用点所有文字突然变得巨大资源映射把 50fp 全局替换恢复语义阶梯编译提示资源不存在token 名与所有者拼写错误或放错模块核对app.float.name标题变大后返回按钮消失Header 约束文本抢占全部宽度保留minWidth: 0与省略大字号下选项被裁切固定高度只改文字没改容器改为最小高度并回归审计一直报告旧 token 未使用定义清单模板残留未删除移除或登记保留理由数字又被新代码写回提交门禁只做一次迁移持续扫描fontSize(number)排查顺序从“资源是否被引用”开始再看资源所有者和容器约束。直接调小所有文字虽然可能让截图暂时不溢出却会再次破坏语义层级。十一、资源化完成的标准是可解释与可回归The_kemusan当前的page_text_font_size50fp没有调用点Index.ets则有 54 次数字字号。真正的治理不是把 54 个数字换成一个资源而是用 caption、正文、动作、选项、标题与强调等角色建立有限阶梯让TypographyTokenAudit同时发现死资源、缺失引用与裸数字回流再在长文本、小窗口和系统大字号下验证容器行为。本文没有修改原工程资源或 ArkUI 页面没有运行hvigorw assembleHap --no-daemon没有生成 HAP也没有在模拟器或真机调整系统字号。9 级候选 token、迁移清单和审计模型属于建议方案最终数值需要结合设计稿、目标窗口、字体缩放策略与无障碍验收后确定。