鸿蒙ArkUI实战:步骤表单与进度指示器

发布时间:2026/6/6 1:44:08

鸿蒙ArkUI实战:步骤表单与进度指示器 长表单拆成多步骤是提升填写完成率的关键 UX 手段。本文用 ArkUI 构建一个三步文章发布流程——自定义步骤指示器、每步独立校验、上一步/下一步导航以及确认页面的一键发布。一、我们要做什么一个发布文章的三步表单第1步基本信息— 输入标题必填最多 30 字 选择分类5 个标签点击选中/取消第2步填写内容— TextArea 输入正文必填不少于 10 个字符最多 500 字第3步确认发布— 只读汇总标题、分类、内容预览点击发布弹窗确认交互点步骤指示器— 顶部三个圆点 连接线已完成绿色对勾当前蓝色数字未完成灰色上一步/下一步— 底部按钮根据当前步骤动态切换第 1 步只有下一步第 3 步只有发布每步校验— 第 1 步标题非空 分类已选第 2 步内容 ≥ 10 字校验不通过 → Toast 提示不跳转发布确认— 第 3 步弹窗确认 → 发布成功 → 重置全部状态回到第 1 步二、状态管理一个currentStep掌控全局StatecurrentStep:number1;Statetitle:string;Statecategory:string;Statecontent:string;整个三步表单只有 4 个State。currentStep决定当前显示哪一步的内容title/category/content是三步共享的表单数据。为什么三个步骤的数据放在同一个页面而不是拆成三个独立页面因为步骤表单的数据是有依赖关系的——第 3 步需要汇总第 1 步和第 2 步的数据。如果拆成三个页面需要通过路由参数传递这些数据增加不必要的复杂性。表单数据的持久性— 用户在第 1 步填了标题 → 点下一步到第 2 步 → 后悔了点上一步回第 1 步 → 标题还在。因为currentStep只是切换了内容区域的可见性并没有销毁状态。数据一直保存在State中。三、交互点1步骤指示器BuilderstepDot(step:number,label:string){Column(){Row(){if(stepthis.currentStep){Text(✓)// 已完成对勾.fontSize(14).fontColor(Color.White)}if(stepthis.currentStep){Text(${step})// 当前步骤数字.fontSize(14).fontWeight(FontWeight.Bold).fontColor(Color.White)}if(stepthis.currentStep){Text(${step})// 未完成灰色数字.fontSize(14).fontColor(AppColors.TEXT_DISABLED)}}.width(28).height(28).borderRadius(14)// 圆形.backgroundColor(stepthis.currentStep?AppColors.PRIMARY:// 已完成蓝色(stepthis.currentStep?AppColors.PRIMARY:#E8E8E8)// 当前蓝色 / 未完成灰色).justifyContent(FlexAlign.Center)Text(label).fontSize(FontSize.CAPTION).fontColor(stepthis.currentStep?AppColors.PRIMARY:AppColors.TEXT_DISABLED).fontWeight(stepthis.currentStep?FontWeight.Medium:FontWeight.Regular).margin({top:Spacing.SM})}.alignItems(HorizontalAlign.Center)}三个视觉状态状态圆圈文字已完成step current蓝色实心 白色 ✓蓝色当前step current蓝色实心 白色数字蓝色加粗未开始step current灰色实心 灰色数字灰色常规连接线BuilderstepLine(from:number){Row().width(40).height(2).backgroundColor(fromthis.currentStep?AppColors.PRIMARY:#E8E8E8).margin({left:Spacing.XS,right:Spacing.XS,bottom:Spacing.XXL})}from是起点步骤的编号1 或 2。连接线 width 40vp 左右 margin XS4vp ≈ 48vp 间距。线在圆圈的水平中间位置margin-bottom: Spacing.XXL24vp让线和圆圈的底部有一个固定的视觉间距。四、交互点2步骤导航与校验4.1 下一步校验privatecanNextStep1():boolean{returnthis.title.trim().length0this.category.length0;}privatecanNextStep2():boolean{returnthis.content.trim().length10;}privategoNext():void{if(this.currentStep1){if(!this.canNextStep1()){promptAction.showToast({message:请填写标题并选择分类,duration:1500});return;}this.currentStep2;}elseif(this.currentStep2){if(!this.canNextStep2()){promptAction.showToast({message:内容不少于10个字符,duration:1500});return;}this.currentStep3;}}每步的校验逻辑独立封装为canNextStep1()/canNextStep2()。校验不通过 → Toast 提示 →return阻止跳转。校验通过 →currentStep切换到下一步。为什么不在点下一步前就显示校验错误因为步骤表单的语义是先填完这一步再进入下一步。在用户还没点下一步之前不判断他填得对不对——他可能正在填写中。过早的校验错误只会让用户焦虑。4.2 “上一步”privategoPrev():void{if(this.currentStep1){this.currentStep--;}}上一步不需要校验——用户回头修改是正常的。只需要currentStep--回到前一页之前填的数据原封不动。4.3 底部按钮的动态切换if(this.currentStep1){Text(上一步)// 第 2、3 步显示.border({width:1,color:AppColors.BORDER}).borderRadius(9999).onClick(()this.goPrev())}if(this.currentStep3){Text(下一步)// 第 1、2 步显示.backgroundColor(AppColors.PRIMARY).borderRadius(9999).onClick(()this.goNext())}if(this.currentStep3){Text(发布)// 仅第 3 步显示.backgroundColor(AppColors.ERROR).borderRadius(9999).onClick(()this.publish())}三个按钮通过if条件渲染上一步和下一步不会同时出现在第 1 步或第 3 步。发布按钮用红色AppColors.ERROR——发布是破坏性的提交操作红色在视觉上让用户审慎对待。五、交互点3发布确认与重置privatepublish():void{promptAction.showDialog({title:确认发布,message:标题${this.title}\n分类${this.category}\n内容长度${this.content.length}字,buttons:[{text:取消,color:AppColors.TEXT_TERTIARY},{text:发布,color:AppColors.PRIMARY}]}).then((result){if(result.index1){this.title;this.category;this.content;this.currentStep1;promptAction.showToast({message:发布成功,duration:1500});}});}弹窗再次确认来自用户的操作——在第 3 步已经看到了全部信息最后一步用弹窗做最终确认。result.index 1表示用户点了发布。发布成功后清空三个表单字段回到第 1 步Toast 反馈这模拟了发布完成可以重新填写下一篇的完整流程闭环。六、第3步的只读汇总this.summaryRow(标题,this.title)this.summaryRow(分类,this.category)// 内容预览Text(this.content).maxLines(5).textOverflow({overflow:TextOverflow.Ellipsis})BuildersummaryRow(label:string,value:string){Row(){Text(label).fontSize(FontSize.BODY).fontColor(AppColors.TEXT_TERTIARY).width(60)Text(value).fontSize(FontSize.BODY).fontColor(AppColors.TEXT_PRIMARY).fontWeight(FontWeight.Medium).layoutWeight(1)}}summaryRow是一个统一的键值对展示组件——左边灰色标签固定 60vp 宽度右边黑色值占据剩余空间。内容预览用maxLines(5)限制高度超出显示省略号——用户在确认页不需要读完整内容只需要确认是自己刚才写的。七、第1步的分类标签Flex({wrap:FlexWrap.Wrap}){ForEach(CATEGORIES,(item:string){Text(item).fontColor(this.categoryitem?Color.White:AppColors.TEXT_SECONDARY).backgroundColor(this.categoryitem?AppColors.PRIMARY:AppColors.BACKGROUND).borderRadius(BorderRadius.SM).padding(...).onClick((){this.categorythis.categoryitem?:item;// 点击切换})})}5 个分类标签用Flex({ wrap: FlexWrap.Wrap })包裹——超过一行自动换行。Row不支持换行Flex支持。这是 ArkUI 布局的一个重要区别。点击行为this.category item ? : item——选中后再次点击可取消。这是一个轻量的单选交互比 RadioGroup 更直观。八、页面结构总结StepperPage (~300 行) ├── 状态层 │ ├── State currentStep: number — 当前步骤 (1/2/3) │ ├── State title: string — 文章标题 │ ├── State category: string — 文章分类 │ └── State content: string — 文章内容 ├── 校验方法 │ ├── canNextStep1() — 标题 分类校验 │ └── canNextStep2() — 内容 ≥ 10 字校验 ├── 导航方法 │ ├── goNext() — 校验通过 → 下一步 │ └── goPrev() — 无校验 → 上一步 ├── 业务方法 │ └── publish() — 弹窗确认 → 发布 → 重置 ├── 步骤指示 Builder │ ├── stepDot(step, label) — 圆形步骤标记 │ └── stepLine(from) — 连接线 ├── 步骤内容 Builder │ ├── stepContent1() — 标题输入 分类选择 │ ├── stepContent2() — 内容 TextArea 字数 │ └── stepContent3() — 只读汇总 发布 └── UI ├── Header ├── 步骤指示器 (3 个 stepDot 2 条 stepLine) ├── 步骤内容 (条件渲染) └── 底部导航按钮九、常见面试题 / 踩坑点9.1FlexvsRow什么时候用哪个Row— 单行排列子元素不换行。适合固定数量的元素如导航栏的按钮Flex wrap— 多行排列子元素超出容器宽度自动换行。适合数量不固定的标签/芯片常见错误在 Row 中放了 7-8 个 Chip/Tag期望换行但 Row 不支持 wrap。改用Flex({ wrap: FlexWrap.Wrap })。9.2 第三步为什么是只读而不是可编辑步骤表单有两种常见模式确认模式本 Demo— 第 3 步只读展示不能修改。要改 → 点上一步回到对应步骤全文模式— 第 3 步可以编辑所有字段等同于一个长表单确认模式的优点每步职责单一校验逻辑不重复只在第 1、2 步校验第 3 步不需要。全文模式适合用户不喜欢来回跳的场景但校验逻辑需要集中在最后一步。9.3 步骤表单的数据会在上一步时丢失吗不会。State变量不会被if (currentStep n)的条件渲染销毁。数据一直保存在组件中切换步骤只是切换了内容的可见性。但如果某个步骤的内容过于复杂如富文本编辑器可以考虑用visibility或.offset隐藏而不是if条件渲染——避免重建组件的开销。9.4 为什么第 2 步的字符数提示用红色/灰色切换Text(this.content.length10?还差${10-this.content.length}个字符:${this.content.length}/500).fontColor(this.content.length10?AppColors.ERROR:AppColors.TEXT_DISABLED)少于 10 字时用红色提示还差 N 个字符——这是一个实时校验反馈让用户知道为什么不让我点下一步。达到 10 字后变回灰色提示消失。这种即时反馈可以减少用户点击下一步后被 Toast 拒绝的挫败感。9.5 步骤指示器的step this.currentStep判断为什么用而不是三种状态的覆盖逻辑step currentStep→ 已完成step 1 current 2 → 第 1 步已完成step currentStep→ 当前step currentStep→ 未完成确保了第 3 步currentStep3时前两步都显示为已完成对勾。十、运行方式代码位于dev/entry/src/main/ets/pages/StepperPage.ets。用 DevEco Studio 打开dev/项目首页点击步骤表单 — 三步发布文章与进度指示即可体验进入页面 → 第 1 步步骤指示器显示蓝色1输入标题 选择分类点击下一步 → 进入第 2 步如未填 → Toast 提示第 2 步输入内容字数不足 10 时显示红色提示还差 N 个字符点击下一步 → 进入第 3 步查看汇总信息点上一步回到第 2 步修改 → 再回来数据不变第 3 步点击发布 → 弹窗确认 → 发布成功 → 回到第 1 步已清空十一、扩展方向步骤指示器动画— 步骤切换时有平滑的颜色过渡animateTo对勾出现时有缩放动画保存草稿— 用 Preferences 持久化表单数据用户退出页面后回来可以继续填写条件步骤— 根据第 1 步的分类选择动态决定是否需要第 2 步如转载分类跳过内容填写步骤校验前置— 第 1 步实时校验标题长度和分类不等到点下一步才报错长表单拆分策略— 超过 10 个字段的长表单自动拆分为 3-4 步每步 2-3 个字段进度百分比— 在步骤指示器下方显示已完成 66%给用户明确的目标感步骤间数据依赖— 第 2 步的选项列表根据第 1 步的选择动态变化如选了技术文章分类 → 第 2 步出现技术标签字段

相关新闻