鸿蒙清新卡片式审美:ArkUI 声明式布局搭出待办清单的统计与输入面板

📅 2026/8/16 4:28:36
鸿蒙清新卡片式审美:ArkUI 声明式布局搭出待办清单的统计与输入面板
实例待办事项清单Todo List风格清新卡片式一、整体布局结构页面采用「统计面板 → 输入区 → 状态切换 → 列表 → 底部操作栏」五段式结构让面板内容丰富但不拥挤┌────────────────────────────────────┐ │ ✅ 待办清单 共 15 项 │ ← 标题栏 ├────────────────────────────────────┤ │ ▢ 未完成 12 ✓ 已完成 3 ⚡高优 4 │ ← 统计卡3 个数字块 ├────────────────────────────────────┤ │ [输入框: 输入新待办…] [分类] [新增] │ ← 输入区 ├────────────────────────────────────┤ │ [全部] [未完成] [已完成] │ ← 状态切换分段控件 ├────────────────────────────────────┤ │ ┌──────────────────────────────┐ │ │ │ ⬜ 完成周报提交 工作 ⚡ │ │ ← 待办卡片多张 │ │ 今天 09:30 │ │ │ │ [改] [完成] [删] │ │ │ └──────────────────────────────┘ │ │ ... │ ├────────────────────────────────────┤ │ 已完成 3 项 ▏▏▏▏▏▏▏▏▏▏ 20% 清空 │ ← 底部进度条 清空已完成 └────────────────────────────────────┘二、各区块说明1. 标题栏左侧✅ 待办清单标题 副标题「优先级排序 · 未完成在前」右侧刷新按钮↻点击重新查询2. 统计卡3 个数字块数据项数据来源展示样式未完成statistics().pending大号蓝色数字已完成statistics().done大号绿色数字高优先级statistics().high大号橙色数字卡片为圆角白底、左右三块均分数字下方有小字标签。3. 输入区组件说明TextInput待办内容输入占位符「输入新待办回车或点新增…」Select分类下拉选择工作 / 生活 / 学习 / 日常优先级选择三选一按钮低 · 中 · 高新增按钮主色填充圆角按钮「 新增」4. 状态切换分段控件三个 Tab全部 / 未完成 / 已完成切换后调用queryByCompleted()刷新列表同时统计卡联动变化。5. 待办卡片列表主体每张卡片包含元素样式完成勾选圈未完成空心圆已完成绿色实心圆 白勾标题未完成黑色加粗已完成灰色 删除线分类标签小圆角底色标签工作蓝/生活绿/学习紫/日常灰优先级高优显示 ⚡ 橙色角标时间灰色小字「MM-DD HH:mm」操作按钮「改」打开编辑弹窗、「完成/取消完成」、「删除」已完成卡片整体置灰、透明度 0.6视觉上弱化。6. 底部进度条完成率进度条已完成/总数百分比右侧「清空已完成」按钮红色小字一键删除全部已完成项三、UI 风格要素风格项取值背景色#F5F7FA浅灰蓝卡片底色白色圆角 12浅阴影主色#3B82F6蓝按钮/选中态成功色#22C55E绿完成态警告色#F97316橙高优先级删除色#EF4444红字体默认 HarmonyOS Sans四、弹窗交互编辑弹窗点击「改」弹出底部弹窗可修改内容、分类、优先级、备注点「保存」调用update()删除确认点「删除」弹出 AlertDialog 二次确认避免误删清空确认清空已完成前同样弹窗确认五、空态与加载场景展示无任何待办居中插画表情 「暂无待办输入上方内容开始吧」切换分类后无数据「该分类下暂无待办」提示条加载中列表顶部显示细进度条六、文章小结本篇设计了五段式页面结构统计面板让顶部信息量充足分段控件提供三种视图卡片承载待办内容底部进度条呈现完成率。整体「清新卡片式」风格统一、信息层级清晰且每个数字、每个标签都直接对应 DAO 查询结果为后续文章的数据填充做好了 UI 容器准备。七、页面信息架构与状态管理详解1. Entry 与 Component入口与组件的边界在 ArkTS 中Entry标记的 struct 是页面级入口可被router.pushUrl()跳转加载Component则声明一个可复用的 UI 组件。本页由三层结构组成Entry// 页面入口可被路由加载Componentstruct TodoPage{// 顶层页面容器StatetodoList:TodoItem[][]// 列表数据Statestatistics:Statistics{pending:0,done:0,high:0}StatecurrentTab:number0// 0全部 1未完成 2已完成StateinputText:string// 输入框内容StateshowLoading:booleanfalse// 加载中开关aboutToAppear(){this.refreshAll()// 页面首次出现即查库}...}2. State 是声明式刷新的「信号源」装饰器作用本页应用Entry标记页面入口可被 router 跳转顶层 TodoPageComponent声明组件可独立复用TodoPage / TodoCardState组件内可变状态变化即触发 UI 重建todoList、currentTab 等Builder复用一段 UI 结构统计数字块、卡片操作按钮核心思想是只改数据、不碰 DOM点「完成」后只需this.todoList[i].completed 1ArkUI 会自动对比新旧状态树并重绘对应卡片开发者无需手动刷新或操作节点。3. 从 DAO 到 UI 的数据流闭环用户点击(新增/完成/筛选) ↓ 调用 TodoDao.insert() / toggleCompleted() / queryByCompleted() ↓ Promise 返回结果 赋值给 State 变量(todoList / statistics) ↓ 状态变化 ArkUI 状态树 diff → 只重建受影响的组件这条链路里DAO 负责「取数」State 负责「存数」ArkUI 负责「画数」三者各司其职页面代码因此保持简洁。八、四大区块的 UI 实现与样式拆解1. 标题栏Flex 两端对齐Row(){Column(){Text(✅ 待办清单).fontSize(22).fontWeight(FontWeight.Bold)Text(优先级排序 · 未完成在前).fontSize(12).fontColor(#9CA3AF)}.alignItems(HorizontalAlign.Start)Blank()// 弹性占位把两侧顶开Button(↻).onClick(()this.refreshAll())}.width(100%).padding(16)要点Blank()是弹性空白组件自动占据剩余宽度实现「左标题、右按钮」的经典顶栏刷新按钮回调refreshAll()重新查库。2. 统计面板三等分数字卡Row(){this.statBlock(未完成,this.statistics.pending,#3B82F6)this.statBlock(已完成,this.statistics.done,#22C55E)this.statBlock(高优先级,this.statistics.high,#F97316)}.padding(12).backgroundColor(Color.White).borderRadius(12).shadow({radius:6,color:rgba(0,0,0,0.06)})三个数字块用Builder抽成公共方法保证样式完全一致BuilderstatBlock(label:string,value:number,color:string){Column(){Text(${value}).fontSize(28).fontWeight(FontWeight.Bold).fontColor(color)Text(label).fontSize(12).fontColor(#6B7280)}.layoutWeight(1).padding({top:12,bottom:12})}layoutWeight(1)让三块在 Row 内均分宽度这是「卡片三等分」的关键也方便日后增加第四块数字。3. 输入区TextInput Select 主色按钮控件关键属性说明TextInputplaceholder / onChange待办内容输入双向绑定 inputTextSelectoptions 数组分类下拉工作/生活/学习/日常ButtonbackgroundColor 主色「 新增」提交并清空输入框Row({space:8}){TextInput({placeholder:输入新待办回车或点新增…,text:this.inputText}).onChange(vthis.inputTextv).layoutWeight(1)Button( 新增).backgroundColor(#3B82F6).onClick(()this.addTodo())}.width(100%).padding(12)4. 列表卡片状态驱动的行样式ForEach(this.todoList,(item:TodoItem){TodoCard({item:item,onToggle:()this.toggleItem(item.id),onDelete:()this.confirmDelete(item.id),onEdit:()this.openEditDialog(item)})},(item:TodoItem)${item.id})已完成卡片的置灰、删除线全部由三元表达式驱动无需写 if/else 分支去操作样式对象.opacity(item.completed1?0.6:1)Text(item.title).decoration({type:item.completed1?TextDecorationType.LineThrough:TextDecorationType.None}).fontColor(item.completed1?#9CA3AF:#1F2937)九、状态筛选与交互设计1. 点击筛选分段控件联动统计Tabs({barPosition:BarPosition.Start}){TabContent(){this.listByState(0)}.tabBar(全部)TabContent(){this.listByState(1)}.tabBar(未完成)TabContent(){this.listByState(2)}.tabBar(已完成)}.onChange(asyncindex{this.currentTabindexthis.todoListawaitTodoDao.queryByCompleted(this.context,index0?-1:index-1)// -1 表示不过滤this.statisticsawaitTodoDao.statistics(this.context)// 统计联动})切换 Tab 触发重新查库列表与统计卡同步刷新形成「筛选 → 查询 → 渲染」的完整闭环保证任何视图下数字都真实可信。2. 删除确认AlertDialog 二次确认AlertDialog.show({title:确认删除,message:删除后不可恢复确定删除这条待办吗,primaryButton:{value:取消,action:(){}},secondaryButton:{value:删除,fontColor:#EF4444,action:()this.deleteItem(pendingId)}})删除是破坏性操作二次确认可避免误触「清空已完成」按钮同样复用该弹窗只是 message 改为「将删除全部 N 条已完成待办」。十、ArkTS 声明式开发的注意事项1. ForEach 的 key 必须唯一且稳定key 生成写法是否推荐原因(item) item.id✅ 推荐主键唯一、不随渲染变化增删不错位(item) item.title⚠️ 谨慎内容可重复、可编辑复用会错乱(item, index) index❌ 避免增删后 index 漂移动画与状态全乱2. 事件绑定传参要用箭头函数// ❌ 错误render 时就立即执行了 deleteItem.onClick(this.deleteItem(item.id))// ✅ 正确箭头函数延迟到点击时才执行.onClick(()this.deleteItem(item.id))3. 状态驱动刷新改「数据」而非改「样式」数组整体替换this.todoList newList触发全量 diff推荐单项更新先splice(i, 1, newItem)整体替换该下标元素禁止直接改State数组元素属性后不赋值——ArkUI 无法感知对象内部的细粒度变化十一、FAQ 常见问题Q1统计数字刷新了列表却没变为什么A多半是列表用了另一个数组如临时变量赋值或queryByCompleted返回新数组后没有整体赋给todoList。检查 State 变量是否被真正替换。Q2删除卡片后动画错乱、行内容串位A几乎都是 ForEach 的 key 用了 index。改用item.id后ArkUI 才能正确识别「谁被删、谁保留」。Q3State 里存对象改了对象属性页面不刷新A需要整体替换对象引用如this.statistics { ...this.statistics, done: n }或将高频变化的字段拆成独立 State。Q4如何让加载进度条只在查询期间显示A用State showLoading在 await 查询前置true、拿到结果后置false配合if (this.showLoading) { LoadingProgress() }条件渲染即可。