鸿蒙原生 ArkTS 布局深度解析:List 空状态占位 emptyState 实战
鸿蒙原生 ArkTS 布局深度解析List 空状态占位 emptyState 实战一、引言为什么「空状态」如此重要在移动应用开发中空状态Empty State是指列表、搜索结果等数据容器在没有任何内容时呈现的界面。很多开发者容易忽视这个边界场景直接将空白页面丢给用户——这会给体验带来明显降级。1.1 空状态的三种常见形态类型说明示例首次使用用户刚安装应用尚无数据待办清单首次打开清空/完成用户主动将数据消耗完毕收件箱全部归档无结果搜索或筛选没有命中数据搜索「XYZ」无匹配项1.2 优秀空状态设计四原则引导性告诉用户这里应该有什么、可以做什么情感化通过图形、文案传递友好态度降低挫败感可操作性提供明确的下一步入口新建、添加、刷新品牌一致性配色与字体与 App 整体调性统一二、HarmonyOS NEXT API 24 的 List emptyState 方案在早期 SDK 中开发者实现空状态需借助if/else条件渲染手动切换。当多个列表各自需要空状态时模板判断代码重复度高。API 24SDK 7.x引入了List组件的.emptyState()属性这是 ArkUI 内置的声明式空状态解决方案。2.1 核心 API/** * 当 List 子组件数量为 0 时自动展示占位 UI * 数据恢复后自动隐藏。 */emptyState(value:CustomBuilder):ListAttribute2.2 与传统方案对比维度if/else 旧方案emptyState API 24代码量每个 List 需额外 if 分支一行链式调用的可维护性多列表时重复判断声明式绑定关注点分离语义清晰度需阅读逻辑分支命名即语义三、场景设计待办清单 App3.1 功能需求展示待办事项列表Checkbox 内容 删除按钮完成态自动添加删除线列表为空时显示友好占位提示提供「清空列表」和「恢复示例数据」用于状态切换单条删除时若列表全部清空弹出反馈3.2 数据模型interfaceTodoItem{id:number;content:string;isDone:boolean;}四、完整代码实现以下代码基于 HarmonyOS NEXT API 24使用List.emptyState()原生 API。/** * 鸿蒙 ArkTS —— List emptyState 空状态占位示例 * 适用HarmonyOS NEXT API 24 (SDK 7.x) */import{promptAction}fromkit.ArkUI;import{hilog}fromkit.PerformanceAnalysisKit;interfaceTodoItem{id:number;content:string;isDone:boolean;}EntryComponentstruct TodoListPage{StateprivatetodoList:TodoItem[][{id:1,content:学习鸿蒙 ArkTS 语法,isDone:true},{id:2,content:掌握 List.emptyState API,isDone:false},{id:3,content:编写完整示例应用,isDone:false},];/** 空状态占位 UI 构建器 */BuilderemptyStateBuilder(){Column(){SymbolGlyph($r(sys.symbol.inbox)).fontSize(72).fontColor([#BBBBBB])Blank()Text(暂无待办事项).fontSize(18).fontColor(#666666).fontWeight(FontWeight.Medium).margin({top:16})Text(点击下方按钮添加一条新的待办吧).fontSize(14).fontColor(#999999).margin({top:8})Button(添加示例数据).type(ButtonType.Capsule).height(40).width(160).margin({top:24}).onClick((){this.loadSampleData();})}.alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center).width(100%).height(100%)}/** 列表项卡片构建器 */BuildertodoItemBuilder(item:TodoItem,index:number){Row(){Checkbox().select(item.isDone).shape(CheckBoxShape.CIRCLE).size({width:22,height:22}).onChange((v:boolean){this.todoList[index].isDonev;})Text(item.content).fontSize(16).fontColor(item.isDone?#BBBBBB:#333333).decoration({type:item.isDone?TextDecorationType.LineThrough:TextDecorationType.None}).margin({left:12}).flexGrow(1)Button({type:ButtonType.Circle,stateEffect:true}){Text(✕).fontSize(16).fontColor(#FF6B6B)}.width(32).height(32).backgroundColor(rgba(255,107,107,0.1)).onClick((){this.deleteItem(index);})}.width(100%).height(56).padding({left:16,right:12}).alignItems(VerticalAlign.Center).backgroundColor(Color.White).borderRadius(12)}build(){Column(){// 标题栏Column(){Text( 我的待办).fontSize(22).fontWeight(FontWeight.Bold).fontColor(#333333)Text(List emptyState 示例).fontSize(12).fontColor(#999999).margin({top:4})}.width(100%).padding({top:24,bottom:12,left:20,right:20})// 核心List emptyState List({space:10}){ForEach(this.todoList,(item:TodoItem,index?:number){ListItem(){this.todoItemBuilder(item,indexasnumber)}},(item:TodoItem)item.id.toString())}.width(100%).layoutWeight(1).padding({left:16,right:16,top:8}).backgroundColor(#F5F5F5).emptyState(this.emptyStateBuilder)// 绑定空状态占位// 底部操作栏Row({space:16}){Button(清空列表).type(ButtonType.Outlined).height(44).layoutWeight(1).fontSize(15).onClick((){this.clearList();})Button(恢复示例数据).type(ButtonType.Capsule).height(44).layoutWeight(1).fontSize(15).onClick((){this.loadSampleData();})}.width(100%).padding(16).backgroundColor(Color.White)}.width(100%).height(100%).backgroundColor(#F5F5F5)}privateshowToast(msg:string):void{try{promptAction.showToast({message:msg,duration:1500});}catch(err){hilog.error(0x0001,Page,showToast failed: %{public}s,JSON.stringify(err));}}privateclearList():void{this.todoList[];this.showToast(列表已清空空状态已触发);}privateloadSampleData():void{constnowDate.now();this.todoList[{id:now1,content:学习鸿蒙 ArkTS 语法,isDone:true},{id:now2,content:掌握 List.emptyState API,isDone:false},{id:now3,content:编写完整示例应用,isDone:false},];}privatedeleteItem(index:number):void{this.todoList.splice(index,1);if(this.todoList.length0)this.showToast(全部清空 );}}五、代码分层解析5.1 状态层State todoListState装饰的todoList是整个页面的数据核心。数组内容变化时ArkUI 自动触发 UI 重渲染this.todoList []→ 清空 →ForEach无数据 →emptyState激活this.todoList [...]→ 恢复 →ForEach有数据 →emptyState隐去5.2 视图层两个Builder构建器渲染条件用途emptyStateBuilder列表为空图标 提示文字 操作按钮todoItemBuilder列表有数据复选框 文本 删除按钮这种拆分让build()函数极其干净——List 只需关心「容器」角色。5.3 控制层.emptyState(this.emptyStateBuilder)这是 API 24 的关键能力。emptyState是一个布林条件属性条件 true列表无数据框架调用 builder 生成占位节点条件 false列表有数据框架销毁占位节点正常渲染列表开发者无需任何 if/else即可获得完整的空状态管理。5.4 交互层状态切换驱动两个底部按钮分别触发clearList()和loadSampleData()。空状态 UI 内部也放置了「添加示例数据」按钮让用户不需要滚动到底部即可恢复数据——这是移动端空状态设计的黄金法则。六、运行时效果预览初始态有数据┌─────────────────────────────┐ │ 我的待办 │ ├─────────────────────────────┤ │ ○ 学习鸿蒙 ArkTS 语法 ✕ │ ← 已完成灰色删除线 │ ● 掌握 List.emptyState ✕ │ ← 未完成 │ ● 编写完整示例应用 ✕ │ ← 未完成 ├─────────────────────────────┤ │ [ 清空列表 ] [ 恢复示例数据 ] │ └─────────────────────────────┘空状态清空后┌─────────────────────────────┐ │ 我的待办 │ ├─────────────────────────────┤ │ │ ← SymbolGlyph 图标 │ 暂无待办事项 │ ← 主提示 │ 点击下方按钮添加新的待办吧 │ ← 副提示 │ [ 添加示例数据 ] │ ← 操作入口 ├─────────────────────────────┤ │ [ 清空列表 ] [ 恢复示例数据 ] │ └─────────────────────────────┘占位 UI 居于 List 区域正中央视觉聚焦、层次分明。七、进阶技巧与最佳实践7.1 配合 LazyForEach大数据量时应使用LazyForEach支持按需加载。emptyState对LazyForEach同样生效——当totalCount为 0 时自动触发。List({space:10}){LazyForEach(this.dataSource,(item:TodoItem){ListItem(){...}},(item:TodoItem)item.id.toString())}.emptyState(this.emptyStateBuilder)7.2 空状态动效过渡通过.transition()为 emptyState 的进出添加微动效.emptyState(this.emptyStateBuilder).transition(TransitionEffect.opacity(0.3))7.3 多 List 独立空状态页面中有多个List时各自绑定自己的Builder即可互不干扰Column(){List(...){...}.emptyState(this.categoryEmpty)List(...){...}.emptyState(this.todayEmpty)}7.4 嵌入更多交互元素空状态中可放置 Refresh 组件、图像动画、推荐词链接等增强引导性。7.5 多语言 / 主题适配使用$r(app.string.xxx)引用资源文件使空状态随系统语言和主题自动切换Text($r(app.string.empty_todo_title)).fontColor($r(sys.color.ohos_id_color_text_primary))八、性能注意事项避免占位内包裹大图片空状态触发时需快速渲染建议使用矢量图标SymbolGlyph / TextBuilder 应为无参函数emptyState绑定的 builder 应为无参如需动态数据通过State间接获取无需嵌套 Scroll占位内容通常不滚动保持精简即可检查数据源类型确保ForEach/LazyForEach的 dataSource 正确绑定避免非预期触发九、常见问题 FAQQemptyState 在有静态子组件时如何工作AemptyState仅根据ForEach/LazyForEach绑定的数据源判断。List 中的静态ListItem不受影响。Q为什么我的 emptyState 不显示A检查三点API 版本 ≥ 24Builder不带参数通过this.xxxBuilder引用ForEach的数据源确实为[]且绑定的是State变量Q可以在 emptyState 中使用路由跳转吗A可以。Builder内部支持所有标准事件处理包括router.pushUrl()和NavPathStack跳转。十、总结HarmonyOS NEXT API 24 的List.emptyState()是 ArkUI 在声明式编程方向上的重要进化。它让开发者以一行代码的增量获得原本需要多层模板判断才能实现的空状态管理能力。核心收益维度收益代码可读性语义化命名一目了然开发效率零模板代码关注点分离维护成本统一管理一处修改全局生效用户体验一致性占位设计专为交互优化更重要的是emptyState体现出「状态驱动 UI」的设计哲学——开发者只需关心what空状态长什么样框架自动处理when何时显示和how如何过渡与回收。希望本文能帮助你深入理解List emptyState的使用方式并在自己的 HarmonyOS NEXT 项目中落地这一优雅的设计模式。本文由 AtomCode 撰写发布于 2026 年 6 月。示例代码基于 HarmonyOS NEXT API 24SDK 7.x兼容 stage 模型。