HarmonyOS APP《画伴梦工厂》开发第14篇:画与进度反馈——Progress 与帧动画

发布时间:2026/7/1 17:55:51

HarmonyOS APP《画伴梦工厂》开发第14篇:画与进度反馈——Progress 与帧动画 第2.6篇动画与进度反馈——Progress 与帧动画难度⭐⭐ 进阶 |前置知识1.3 State 与状态管理 |涉及源文件products/default/src/main/ets/pages/RecognitionWaitingPage.ets一、引言当用户完成了涂鸦或照片采集点击生成动画后应用进入RecognitionWaitingPage。在这个页面上AI 正在后台处理图像、识别内容、生成视频帧。整个过程可能持续数秒到数十秒。对儿童用户而言一个静止的加载中…页面是不可接受的。没有视觉反馈小朋友会认为应用卡住了进而反复点击或关闭应用。画伴梦工厂的等待页面通过三层进度反馈机制来解决这个问题Progress 进度条—— 展示整体进度百分比帧动画气泡—— 动态变化的 Circle 组件产生跳动感步骤条—— 分阶段展示任务进度让用户知道现在在做什么本文将深入分析这三层机制的设计与实现。二、状态设计Stateprivateprogress:number12;StateprivateactiveStep:number0;StateprivatestatusText:string正在准备生成任务;Stateprivatefailed:booleanfalse;Stateprivatecompleted:booleanfalse;StateprivateanimationFrame:number0;StateprivatewaitingTip:stringWAITING_TIPS[0];状态类型初始值作用progressnumber12进度百分比 0-100activeStepnumber0当前激活的步骤索引0-3statusTextstring‘正在准备生成任务’主要状态文本failedbooleanfalse是否生成失败completedbooleanfalse是否生成完成animationFramenumber0帧动画的当前帧0-3waitingTipstringWAITING_TIPS[0]底部提示文案这些状态通过State 装饰器驱动 UI 自动刷新。ArkUI 的响应式系统会检测状态变化只更新受影响的 UI 部分保证了动画性能。三、Progress 组件详解3.1 基础用法Progress({value:this.progress,total:100,type:ProgressType.Linear}).width(84%).height(8).color(this.mint)// 前景色 #42CDA3.backgroundColor(#ECECF6)// 背景色.borderRadius(6).margin({top:12})参数说明参数说明value当前进度值需在 0 到 total 之间total总进度值type进度条类型ProgressType.Linear线性或ProgressType.Circle圆形Progress 类型一览类型说明适用场景Linear水平线性进度条通用进度展示Circle圆形进度环需要节省空间或强调百分比的场景3.2 进度驱动逻辑进度由setInterval定时器驱动模拟 AI 生成进度privatestartWaitingTimer(){if(this.timerId0){clearInterval(this.timerId);}this.timerIdsetInterval((){if(this.failed||this.completed){clearInterval(this.timerId);this.timerId-1;return;}this.animationFrame(this.animationFrame1)%4;this.waitingTipWAITING_TIPS[this.animationFrame%WAITING_TIPS.length];if(this.progress92){this.progressMath.min(92,this.progress3);}else{this.progressMath.min(97,this.progress1);}this.activeStepMath.min(3,Math.floor(this.progress/28));},1200);}进度条设计考量起始值 12不让用户看到从 0 开始的假象让等待显得已经进行了一段时间。分段速度progress 92时每次 3 92时每次 1。前端进度慢下来营造接近完成的真实感。上限 97预留最后的 3% 给真正的完成回调不会出现99% 卡住的尴尬。1200ms 间隔约 1.2 秒更新一次节奏舒缓不急促。3.3 完成与失败的处理当 AI 生成完成或失败时// 成功this.progress100;this.completedtrue;this.statusText视频已生成并保存到作品;// 失败this.failedtrue;this.statusText生成失败getErrorMessage(error);定时器会检测failed或completed状态及时clearInterval停止更新。四、帧动画气泡LoadingBubbles4.1 实现代码BuilderprivateLoadingBubbles(){Row(){Circle().width(this.animationFrame0?24:16).height(this.animationFrame0?24:16).fill(this.sunshine)// #FFB84D 黄色.opacity(this.animationFrame0?1:0.55)Circle().width(this.animationFrame1?24:16).height(this.animationFrame1?24:16).fill(this.mint)// #42CDA3 绿色.opacity(this.animationFrame1?1:0.55).margin({left:12})Circle().width(this.animationFrame2?24:16).height(this.animationFrame2?24:16).fill(this.brandPurple)// #7657F3 紫色.opacity(this.animationFrame2?1:0.55).margin({left:12})}.height(34).alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center).margin({top:12})}4.2 动画原理这是一个无动画 API 的帧动画方案通过定时器切换animationFrame状态驱动 Circle 组件的大小和透明度变化animationFrame 0 → 圆圈1 放大(24) 高不透明度(1)圆圈2、3 缩小(16) 低不透明度(0.55) animationFrame 1 → 圆圈2 放大 高不透明度圆圈1、3 缩小 低不透明度 animationFrame 2 → 圆圈3 放大 高不透明度圆圈1、2 缩小 低不透明度 animationFrame 3 → 全部缩小 低不透明度短暂休息帧为什么不用 animateTo 或 animator简单可靠ArkTS 的StatesetInterval方案没有复杂的学习曲线逻辑直观。完全可控每一帧的状态都可以精确控制不像 Property Animation 存在中间插值。性能友好只变更尺寸和透明度不涉及布局重排ArkUI 可以高效地执行属性更新。4.3 与外围动画的配合除了气泡还有背景圆环动画Circle().width(126this.animationFrame*6).height(126this.animationFrame*6).fill(#EAF8F0).opacity(0.72)中央百分比数字下方的圆环会随animationFrame递增而周期性扩大每次 6产生呼吸效果与气泡形成视觉层次感。五、步骤条StepRow5.1 实现代码constWAITING_STEPS:string[][看看画里有什么,想一想怎么动,画出动画片段,保存到我的作品];BuilderprivateStepRow(step:string,index:number){Row(){Text((index1).toString()).fontSize(12).fontWeight(FontWeight.Bold).fontColor(this.activeStepindex?#FFFFFF:#8A8FA4).width(30).height(30).backgroundColor(this.activeStepindex?this.mint:#ECECF6).borderRadius(15)Text(step).fontSize(13).fontColor(this.activeStepindex?this.ink:#8A8FA4).layoutWeight(1).margin({left:12})Text(this.activeStepindex?完成:(this.activeStepindex?进行中:等待)).fontSize(11).fontColor(this.activeStepindex?this.mint:#9AA0B5)}.width(100%).padding(12).backgroundColor(#FFFFFF).borderRadius(14).margin({top:10})}5.2 三种状态设计步骤条的每个步骤有三种视觉状态由activeStep与index的比较决定条件状态圆形编号步骤文字右侧标签activeStep index已完成绿色底 白字深色“完成” 绿色文字activeStep index进行中绿色底 白字深色“进行中” 绿色文字activeStep index等待中灰色底 灰字灰色“等待” 灰色文字5.3 进度与步骤的映射this.activeStepMath.min(3,Math.floor(this.progress/28));每个步骤覆盖约 28% 的进度区间进度范围activeStep步骤0 - 270看看画里有什么28 - 551想一想怎么动56 - 832画出动画片段84 - 1003保存到我的作品这样用户的进度感知从一个模糊的百分比变成了四个清晰的阶段体验更加透明。六、页面中央大进度指示Stack(){Circle().width(168).height(168).fill(#FFF0D6)Circle().width(126this.animationFrame*6).height(126this.animationFrame*6).fill(#EAF8F0).opacity(0.72)Column(){Text(this.progress.toString()%).fontSize(32).fontWeight(FontWeight.Bold).fontColor(this.brandPurple)Text(this.completed?完成啦:制作中).fontSize(13).fontWeight(FontWeight.Bold).fontColor(this.mint).margin({top:4})}.alignItems(HorizontalAlign.Center)}视觉层次从底到顶底层圆#FFF0D6暖黄固定大小 168×168作为衬底中层圆#EAF8F0浅绿随animationFrame周期性缩放126-144半透明产生呼吸感顶层文字大号百分比数字 状态文字七、生命周期管理aboutToAppear(){// ... 获取 Router 参数 ...this.startWaitingTimer();this.startGeneration();}aboutToDisappear(){if(this.timerId0){clearInterval(this.timerId);this.timerId-1;}}为什么必须清理定时器如果不清理会出现以下问题内存泄漏定时器的回调持有组件引用阻止 GC 回收。状态泄漏离开页面后定时器仍在运行试图更新已销毁组件的 State导致 ArkUI 警告或异常。重复定时器用户反复进入该页面会创建多个定时器实例进度更新速度翻倍。最佳实践在aboutToAppear中创建定时器在aboutToDisappear中清理定时器使用timerId追踪定时器状态创建前先清理旧实例八、底部按钮的状态联动Button(this.failed?重试生成:(this.completed?查看视频结果:正在做动画...)).width(90%).height(46).fontSize(15).fontWeight(FontWeight.Bold).fontColor(#FFFFFF).backgroundColor((this.completed||this.failed)?this.brandPurple:#A9A0D8).borderRadius(23).margin({top:20}).onClick((){if(this.failed){// 重置所有状态重新生成this.progress12;this.activeStep0;this.animationFrame0;this.waitingTipWAITING_TIPS[0];this.startWaitingTimer();this.startGeneration();}elseif(this.completed){// 跳转到结果页this.getUIContext().getRouter().pushUrl({url:pages/RecognitionResultPage,params:{...}});}})按钮的文本和颜色均与状态联动状态按钮文字按钮颜色点击行为进行中“正在做动画…”浅紫#A9A0D8不可点击完成“查看视频结果”品牌紫#7657F3跳转结果页失败“重试生成”品牌紫#7657F3重置并重新生成这种设计让用户在任何状态下都知道现在该做什么。九、状态与 UI 联动全景┌─────────────────┐ │ setInterval │ │ 每 1200ms 触发 │ └────────┬────────┘ │ ┌──────────────┼──────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │progress3│ │frame1%4 │ │activeStep│ │ (或1) │ │ │ │ p/28 │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Progress │ │Bubbles │ │ StepRow │ │ 百分比显示│ │大小/透明度│ │三种状态 │ │ Linear │ │三色圆圈 │ │完成/进行/│ │ │ │呼吸动画 │ │等待 │ └──────────┘ └──────────┘ └──────────┘三层进度反馈同时更新但各自关注不同的状态变量互不干扰。这体现了 ArkUI 响应式编程的优雅之处。十、总结本文深入分析了 RecognitionWaitingPage 中三层进度反馈机制的实现反馈层组件驱动方式视觉效果进度条Progressprogress状态线性进度百分比帧动画Circle× 3animationFrame状态气泡跳动 圆环呼吸步骤条自定义BuilderactiveStep状态完成/进行中/等待三态设计原则让等待有信息量用户不仅知道要等多久还知道等的是什么。动画给予安全感动态的 UI 让用户确信应用仍在工作。状态透明可预期步骤条和百分比让进度可量化减少焦虑。生命周期安全及时清理定时器防止内存泄漏和状态异常。对于儿童应用而言这层等待体验的设计甚至比 AI 生成本身更重要——它直接决定了用户会不会在过程中放弃。动手挑战尝试在LoadingBubbles中加入第四种颜色圆圈或将气泡动画改为沿弧形轨迹运动。也可以尝试使用animateTo隐式动画替代帧切换体验两种方案的差异。

相关新闻