Harmony os 技术实战|拼豆制图02:50 张图纸的 Repository 与轻量预览 Harmony os 技术实战拼豆制图0250 张图纸的 Repository 与轻量预览图库从 7 张扩到 50 张后最容易遇到的问题不是数据不够而是页面一打开就把所有完整编号矩阵都渲染出来。拼豆图纸每张都可能有 70 x 70 个格子如果列表页把这些格子全部创建成 UI用户只是滑动图库却要替详情页付出成本。这篇文章会把问题拆到能落地的层面重点解决把图纸种子、资源矩阵和页面展示分开。列表页使用 previewCells详情页才使用 chartCells。用统计函数复算颜色数量和拼豆总数避免手填失真。保留没有真实矩阵时的程序化图纸生成能力。问题不是 50 张图而是 50 张完整矩阵拼豆制图的图库包含动漫人物、游戏人物、爱豆、场景、潮玩盲盒等分类。列表页需要快速展示封面、标题、难度、色数和收藏按钮详情页才需要每一格色号、坐标、图例和放大查看。如果把这两种需求混成一个对象在列表页就会过度计算。项目里已经把PatternRepository放在 services 层这是一个正确方向。它既不是简单常量表也不是 UI 组件它负责把种子数据、真实矩阵资产和颜色统计拼成页面可消费的Pattern。这样图库页只管渲染卡片编号图纸页只管展示完整施工图。落地时可以先抓三个信号Repository的职责是否只在一个层级里被定义而不是页面、服务和资源各写一份。Pattern相关状态是否能从用户入口一路追到结果页中间没有隐式副作用。遇到空数据、取消操作或边界输入时页面是否还能停在可继续操作的状态。Repository 应该拥有数据组装权Repository 的边界可以定得更清楚它接收图纸 ID 和加载策略返回稳定的业务对象。页面不关心矩阵来自脚本、资源文件还是程序化算法页面只关心对象里有没有 previewCells、chartCells 和 colorStats。决策点推荐做法避免的问题列表展示读取previewCells列表滑动卡顿详情展示进入编号页再取完整chartCells首屏承担全部矩阵成本颜色统计从格子数组复算手填统计和实际图纸不一致资源缺省保留程序化生成兜底某张图缺资源导致页面空白这张表真正约束的是变更顺序先固定“列表展示”的归属再处理“详情展示”的输入输出最后围绕“颜色统计”做回归。只要这三处没有漂移后续增加页面、资源或参数时改动就不会一路扩散到无关模块。实际排查时也建议按这个顺序记录结论哪一层接收输入、哪一层生成结果、哪一层负责失败后的恢复。记录得越具体下一轮迭代越不容易把已经稳定的路径改坏。Pattern 模型要覆盖列表和施工图模型要同时服务列表和详情但不要让页面猜字段含义。previewCells是小尺寸预览chartCells是施工图矩阵二者都使用同一个BeadCell这样渲染组件可以复用。1. 模型同时覆盖预览和完整图纸一个Pattern可以被列表页和详情页共用但字段含义必须区分清楚。exportinterfaceBeadCell{id:string;row:number;col:number;colorId:string;colorCode:string;hex:string;isEmpty:boolean;}exportinterfacePattern{id:string;title:string;category:string;width:number;height:number;previewCells:BeadCell[];chartCells:BeadCell[];colorStats:BeadColorStat[];}previewCells解决列表页轻量展示chartCells解决施工图细节。两者共用BeadCell避免写两套渲染逻辑。按需创建预览和完整图纸Repository 的核心不是返回数组而是把来源不同的数据统一成Pattern。真实矩阵存在时使用资源矩阵没有资源时使用程序化图形保证每张图都能进入详情页。2. Repository 暴露列表和按 ID 查询页面不用知道种子数组在哪里也不用关心真实矩阵是否存在。exportclassPatternRepository{staticgetPatterns():Pattern[]{constseedsPatternRepository.createSeeds();constresult:Pattern[][];for(leti0;iseeds.length;i){result.push(PatternRepository.createPattern(seeds[i],false));}returnresult;}staticgetPatternById(id:string):Pattern|null{constseedsPatternRepository.createSeeds();for(leti0;iseeds.length;i){if(seeds[i].idid){returnPatternRepository.createPattern(seeds[i],true);}}returnnull;}}列表读取时includeFullChartfalse详情读取时才打开完整矩阵。这个参数把性能策略放在 Repository而不是散在页面分支里。矩阵编码要能被脚本稳定生成图库页的渲染策略应该克制。列表卡片用预览格子和封面信息不直接渲染完整图纸。这样搜索和分类切换时只需要处理轻对象。3. 真实矩阵和程序化图纸走同一出口不是每张图一开始都有真实矩阵所以需要一个统一的创建函数。privatestaticcreatePattern(seed:PatternSeed,includeFullChart:boolean):Pattern{constassetChartPatternAssetCharts.get(seed.id);constpaletteassetChartnull?seed.palette:PatternRepository.assetPalette(seed.id,assetChart.colors);constpreviewCellsassetChartnull?PatternRepository.createCells(${seed.id}-preview,palette,seed.variant,16):PatternRepository.createCellsFromRows(${seed.id}-preview,palette,assetChart.previewRows);constchartCellsassetChart!nullincludeFullChart?PatternRepository.createCellsFromRows(seed.id,palette,assetChart.chartRows):previewCells;returnPatternRepository.buildPattern(seed,palette,previewCells,chartCells);}这里的重点是出口一致页面拿到的永远是Pattern。资源矩阵、程序化兜底、轻量预览都被收在 Repository 内部。统计结果从格子反推统计信息不要做成静态文本。色号数量、每色颗数、总颗数都可以从格子里复算导出图和详情页也会得到同一组数字。4. 用字符矩阵表达颜色索引资源矩阵适合脚本生成字符编码比直接写 4900 个对象更容易维护。privatestaticcreateCellsFromRows(id:string,palette:PaletteColor[],rows:string[]):BeadCell[]{constcells:BeadCell[][];for(letrow0;rowrows.length;row){constsourceRowrows[row];for(letcol0;colsourceRow.length;col){consttokensourceRow.substring(col,col1);constcolorIndexPatternRepository.assetColorIndex(token);constcolorcolorIndex0?null:palette[colorIndex];cells.push(PatternRepository.createCell(id,row,col,color));}}returncells;}字符.表示空格数字和字母表示颜色索引。脚本只要输出稳定字符串就能被 Repository 转成统一的格子对象。页面只消费业务对象批量生成后的矩阵资源需要有稳定命名。文件名、图纸 ID 和资源映射要保持同一套规则否则 50 张图扩到 100 张时最先出问题的是错配而不是算法。5. 统计从格子反推图例和总颗数不要手写避免换图后忘记同步。privatestaticcountColors(palette:PaletteColor[],cells:BeadCell[]):BeadColorStat[]{conststats:BeadColorStat[][];for(leti0;ipalette.length;i){constcolorpalette[i];letcount0;for(letcellIndex0;cellIndexcells.length;cellIndex){if(cells[cellIndex].colorIdcolor.id){count;}}stats.push({colorId:color.id,colorCode:color.code,colorName:color.name,hex:color.hex,count});}returnstats;}统计函数拥有完整格子输入因此能服务详情页、导出图和个人页作品统计。后续如果增加材料清单也可以从这里派生。验证图库加载路径实际项目里验证不能只看页面有没有打开。更稳的做法是把入口、状态、边界数据和失败路径都走一遍尤其是拼豆图纸这种“看起来能显示放大后才暴露问题”的功能。验证前建议准备一组固定样本一条正常路径、一条空数据路径、一条失败路径再加一条连续操作路径。这样每次改动都能比较同一批场景不会只凭当前页面肉眼感觉判断。如果涉及屏幕尺寸、资源替换或系统能力还要保留修改前后的截图和关键输入方便回退时确认差异来自哪里。hvigor assembleHap--no-daemonWrite-Host手动验证图库滚动 - 分类切换 - 打开编号图 - 返回图库 - 再打开另一张图图库首次打开时不应明显卡顿分类切换后卡片高度和列数保持稳定。随机打开 5 张图纸确认详情页宽高、色数、总颗数与图例一致。缺少真实矩阵的图纸也能进入编号图纸页不能出现空白详情。搜索结果中的图纸点击后仍能读取完整 chartCells。批量替换资源后图纸 ID 和矩阵资源要一一对应。常见问题和处理现象先看哪里处理方式图库滑动卡顿列表页是否渲染完整矩阵列表只渲染 previewCells 或封面图详情色号为空assetColorIndex 和 palette 长度检查矩阵字符是否越界图例数量不对countColors 输入的是预览还是完整图详情和导出使用 chartCells 统计某张图打不开PatternAssetCharts.get 返回值缺资源时回退程序化图纸继续扩展图库时的做法当图库继续扩容可以把种子数据拆成 JSON5 或生成脚本输出的 ArkTS 文件Repository 只保留解析和统计逻辑。若后续支持用户下载主题包也可以把PatternAssetCharts.get替换成异步读取本层接口仍然返回同样的Pattern。继续推进时建议保持三条约束先让现有主路径可回归再拆更细的组件或服务。新增状态必须能说明来源、更新时机和失败后的保留策略。新增资源或配置要能从页面反查到生成来源避免后期只靠人工记忆维护。小结图库稳定的核心是按场景给数据减重。列表页要快详情页要准统计要能复算。Repository 负责把资源和算法收成统一模型页面就不会被 50 张图纸的矩阵细节拖住。