鸿蒙应用开发实战【19】— 统计卡片组件:数字展示、颜色语义与点击导航 鸿蒙应用开发实战【19】— 统计卡片组件数字展示、颜色语义与点击导航前言欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net号码助手首页顶部有三张统计卡片分别显示「待换绑」「待注销」「已停用」三个维度的数量。每张卡片有一个带颜色背景的图标、一个醒目的数字以及点击后跳转到对应状态列表的交互。这个看似简单的组件涉及颜色语义系统、Builder参数化组件、布局等分技巧、animateTo 数字动效等多个关键知识点。本篇涵盖StatCard Builder 参数化设计、AppColors 颜色语义体系、WARN/DANGER/MUTED 三色语义、圆角图标容器实现、layoutWeight 等分布局、数字大字样式、animateTo 数字切换动效、onClick 状态筛选导航。图1StatCard 三卡等分布局、WARN/DANGER/MUTED 三色语义、animateTo 数字动效流程一、统计卡片整体设计1.1 视觉规格属性规格卡片背景#E6FFFFFF白色高亮卡 AppColors.CARD_B卡片圆角radius: 16图标容器26×26 vpradius: 8半透明色背景数字字号fontSize: 22fontWeight: BOLD标签字号fontSize: 11fontColor: TEXT_2三卡等分父 Row 的每张卡用.layoutWeight(1)1.2 三维语义颜色// 三张卡对应的颜色语义this.StatCard(↔,this.pendingSwitch,待换绑,AppColors.WARN_BG,AppColors.WARN,待换绑)this.StatCard(×,this.pendingCancel,待注销,AppColors.DANGER_BG,AppColors.DANGER,待注销)this.StatCard(–,this.disabledCount,已停用,AppColors.MUTED_BG,AppColors.MUTED,已停用)状态图标色背景色bg含义待换绑WARN #DB8A00警告黄WARN_BG #21DB8A00需要用户主动换绑卡号待注销DANGER #E5395B危险红DANGER_BG #1FE5395B需要联系服务商注销已停用MUTED #8B93A7静默灰MUTED_BG #0F141E3C已不再使用无需紧急处理二、AppColors 颜色语义体系2.1 语义色定义// AppColors.ets — 辅助语义色exportclassAppColors{/** 警告黄 */staticreadonlyWARN:string#DB8A00/** 警告背景 rgba(219,138,0,.13) — ArkUI #AARRGGBB 格式 */staticreadonlyWARN_BG:string#21DB8A00/** 危险红 */staticreadonlyDANGER:string#E5395B/** 危险背景 rgba(229,57,91,.12) */staticreadonlyDANGER_BG:string#1FE5395B/** 静默灰不再活跃 */staticreadonlyMUTED:string#8B93A7/** 静默背景 rgba(20,30,60,.06) */staticreadonlyMUTED_BG:string#0F141E3C}2.2 ArkUI 颜色格式提醒// ArkUI 的颜色格式是 #AARRGGBBAlpha 在最前不是 CSS 的 #RRGGBBAA// 示例rgba(219,138,0, 0.13) → Alpha0.13*255≈33 → 0x21// 所以 WARN_BG #21DB8A00// ^^ — Alpha0x2133/255≈13%// ^^^^^^ — RGBDB8A00警告黄// Alpha 十六进制速查// 0xFF100% 0xCC80% 0x9960% 0x6640% 0x3320% 0x1A10%// 0x21≈13% 0x1F≈12% 0x14≈8% 0x0F≈6%2.3 为什么要语义分离// ❌ 反模式直接写死颜色字符串Column(){Text(icon).fontColor(#DB8A00)// 危险多处散落难以统一调整}.backgroundColor(#21DB8A00)// 修改时要找所有地方// ✅ 正确通过 AppColors 统一管理语义色Column(){Text(icon).fontColor(AppColors.WARN)}.backgroundColor(AppColors.WARN_BG)// 一处修改全局生效三、StatCard Builder 完整实现3.1 完整代码// HomePage.ets — StatCard Builder 方法BuilderprivateStatCard(icon:string,num:number,label:string,bg:string,fg:string,status:string){Column(){// ① 图标容器小圆角正方形半透明色背景Column(){Text(icon).fontSize(14).fontColor(fg).fontWeight(FontWeight.Bold)}.width(26).height(26).borderRadius(8).backgroundColor(bg)// WARN_BG / DANGER_BG / MUTED_BG.justifyContent(FlexAlign.Center).margin({bottom:10})// ② 数字主要信息醒目大字Text(${num}).fontSize(22).fontWeight(AppFonts.WEIGHT_BOLD).fontColor(AppColors.TEXT).lineHeight(22).margin({bottom:4})// ③ 标签辅助说明Text(label).fontSize(11).fontColor(AppColors.TEXT_2)}.layoutWeight(1)// 三卡等分宽度.padding({top:12,bottom:12,left:10,right:10}).alignItems(HorizontalAlign.Start).backgroundColor(AppColors.CARD_B).border({width:1,color:AppColors.LINE,radius:16}).onClick((){constparams:StatusRouteParams{status:status}this.navigate(pages/StatusListPage,params)})}3.2 调用方式// 父容器Row 横排space: 10 作为间距Row({space:10}){this.StatCard(↔,this.pendingSwitch,待换绑,AppColors.WARN_BG,AppColors.WARN,待换绑)this.StatCard(×,this.pendingCancel,待注销,AppColors.DANGER_BG,AppColors.DANGER,待注销)this.StatCard(–,this.disabledCount,已停用,AppColors.MUTED_BG,AppColors.MUTED,已停用)}.width(100%).padding({left:16,right:16}).margin({top:4,bottom:16})四、layoutWeight 等分布局4.1 三卡等分原理// Row 父容器总宽度 屏幕宽度 - 左右 padding - 两个 space// 减去 space: 10 * 2 20vp减去 padding: 16*2 32vp// 剩余 (屏幕宽度 - 32 - 20) / 3 —— 每张卡的宽度// .layoutWeight(1) 对等分非常有用// 三张卡都写 layoutWeight(1) → 1:1:1 等分剩余空间Row({space:10}){CardA().layoutWeight(1)CardB().layoutWeight(1)CardC().layoutWeight(1)}// 如果要 2:1:1 比例Row({space:10}){CardA().layoutWeight(2)// 占 50%CardB().layoutWeight(1)// 占 25%CardC().layoutWeight(1)// 占 25%}4.2 避免使用固定宽度// ❌ 反模式写死宽度多屏尺寸适配差Column().width(100)// 在不同屏幕宽度下看起来不一致// ✅ 推荐layoutWeight 自适应Column().layoutWeight(1)// 随父容器自适应五、数字动效animateTo5.1 为什么要动效数字从 0 变为实际数字如 12时直接刷新会有突兀感。通过animateTo可以实现数字平滑切换的视觉效果。5.2 带动效的数字更新// 在 loadData 成功后使用 animateTo 驱动数字变化StatependingSwitch:number0StatependingCancel:number0StatedisabledCount:number0privateasyncloadData():Promisevoid{try{constcountsawaitAppBindingDao.countByStatus()constswcounts.find((c:StatusCount)c.status待换绑)?.count??0constcacounts.find((c:StatusCount)c.status待注销)?.count??0constdicounts.find((c:StatusCount)c.status已停用)?.count??0// 使用 animateTo 触发数字动效animateTo({duration:400,curve:Curve.EaseOut},(){this.pendingSwitchswthis.pendingCancelcathis.disabledCountdi})}catch(e){console.error(loadData failed:,JSON.stringify(e))}}5.3 animateTo 参数animateTo({duration:400,// 动画时长毫秒curve:Curve.EaseOut,// 缓动曲线EaseOut 先快后慢delay:0,// 延迟启动毫秒iterations:1,// 循环次数-1 无限循环playMode:PlayMode.Normal},(){// 在这里修改 State 变量 → ArkUI 自动产生动画过渡this.pendingSwitchnewValue})5.4 常用 Curve 对比Curve特点适用场景Curve.Linear匀速进度条Curve.EaseIn先慢后快元素飞入Curve.EaseOut先快后慢数字展示 ✅Curve.EaseInOut两端慢中间快通用过渡Curve.Spring弹簧效果元素弹出六、点击跳转到状态列表6.1 路由参数类型声明// ArkTS 要求对象字面量有类型声明不能是裸对象interfaceStatusRouteParams{status:string}// 正确的跳转写法.onClick((){constparams:StatusRouteParams{status:status}// 有类型声明this.navigate(pages/StatusListPage,params)})// ❌ 错误ArkTS 编译报错.onClick((){this.navigate(pages/StatusListPage,{status:status})// ArkTS 2.0: Object literal must correspond to some declared class or interface})6.2 接收端读取参数// StatusListPage.ets — 接收参数EntryComponentstruct StatusListPage{privatestatus:stringonPageShow():void{constparamsrouter.getParams()asStatusRouteParamsif(params?.status){this.statusparams.status}}}七、完整数据加载流程// HomePage.ets — 完整 loadDataprivateasyncloadData():Promisevoid{if(this.rows.length0){this.loadingtrue// 首次加载显示骨架}try{// ① 加载卡号列表用于构建 AppRowthis.cardsawaitCardDao.listAll()constcardLabelMapnewMapnumber,string()for(constcofthis.cards){cardLabelMap.set(c.id??0,c.label)}// ② 加载各状态数量 → 更新统计卡数字constcounts:StatusCount[]awaitAppBindingDao.countByStatus()animateTo({duration:400,curve:Curve.EaseOut},(){this.pendingSwitchcounts.find((c:StatusCount)c.status待换绑)?.count??0this.pendingCancelcounts.find((c:StatusCount)c.status待注销)?.count??0this.disabledCountcounts.find((c:StatusCount)c.status已停用)?.count??0})// ③ 加载所有绑定记录 → 构建 AppRow含卡号标签constbindingsawaitAppBindingDao.listAll()this.rowsbindings.map((b:AppBindingEntity):AppRow({binding:b,cardLabel:cardLabelMap.get(b.card_id)??}))}catch(e){console.error(loadData failed:,JSON.stringify(e))}finally{this.loadingfalse}}八、本篇小结知识点核心要点StatCard Builder参数化设计icon/num/label/bg/fg/status 6 个参数颜色语义WARN黄/DANGER红/MUTED灰背景色加 Alpha#AARRGGBBArkUI 颜色格式Alpha 在最前不同于 CSSlayoutWeight(1)三卡等分宽度自适应屏幕animateTo数字变化时平滑动效curve: EaseOutStatusRouteParamsArkTS 要求对象字面量有 interface 声明参考资料鸿蒙应用开发实战【14】— 毛玻璃卡片颜色格式深度解析鸿蒙应用开发实战【05】— 首页开发与状态管理鸿蒙应用开发实战【20】— 批量操作栏UI选择模式实现animateTo 动画 APICurve 缓动曲线枚举Builder 装饰器参考layoutWeight 属性router 路由参数传递如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netHarmonyOS animateTo 文档https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-explicit-animationAppColors 设计令牌https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-resource-access