HarmonyOS应用开发实战:猫猫大作战-HUD 的容器拆分、三段横排、状态绑定、层序控制
前言游戏页的主角是棋盘和猫咪但「HUDHead-Up Display」——屏幕顶端那个展示得分、连击、时间的栏——是玩家感知游戏进度的核心反馈区。一个 HUD 要做得信息清晰但不抢戏、随状态实时更新、与棋盘棋子正确叠层涉及Builder拆分、Column嵌套、State绑定、Stack层序四个知识点。本篇以「猫猫大作战」游戏页顶部 HUD 的得分栏为锚点把 HUD 的容器拆分、三段横排、状态绑定、层序控制讲透。读完本篇你将能独立写出得分/预告/时间三栏 HUD、实时状态绑定 HUD、悬浮顶层 HUD三种实战套路。提示本系列不讲 ArkTS 基础语法与环境搭建假设你已跟完第 1–10 篇。一、场景拆解GameHUD 三栏结构打开entry/src/main/ets/pages/Index.ets的GameHUD// 来源entry/src/main/ets/pages/Index.ets GameHUD() Builder GameHUD() { Row() { // 左栏得分 Column() { Text(得分).fontSize(10).fontColor(#95A5A6) Text(${this.score}).fontSize(20).fontColor(#2C3E50).fontWeight(FontWeight.Bold) }.alignItems(HorizontalAlign.Start).layoutWeight(1) // 中栏预告区下一个猫咪 Column() { Text(下一个).fontSize(10).fontColor(#95A5A6) Circle({ width: 24, height: 24 }).fillColor(#FFC107).margin({ top: 4 }) }.alignItems(HorizontalAlign.Center).layoutWeight(1) // 右栏时间 Column() { Text(时间).fontSize(10).fontColor(#95A5A6) Text(this.formatTime()).fontSize(20).fontColor(#2C3E50).fontWeight(FontWeight.Bold) }.alignItems(HorizontalAlign.End).layoutWeight(1) } .width(100%).padding({ left: 16, right: 16, top: 12, bottom: 12 }) .backgroundColor(rgba(255,255,255,0.9)) }HUD 三栏规格拆解栏内容对齐layoutWeight视觉左得分 数字Start1数字左对齐中下一个 圆形预告Center1圆居中右时间 数字End1数字右对齐关键经验三栏用layoutWeight(1)均分宽度——每栏占 1/3对齐不同但宽度等。这是 HUD 三栏的甜区。二、Builder 拆分 HUD 为独立单元Builder GameHUD() { Row() { /* ... 三栏 ... */ } }Builder是 ArkUI 的「局部构建函数」——把一段 UI 结构封装成可复用的 Builder在build()里像函数一样调用build() { Stack() { // ... 棋盘、猫咪 GameHUD() // 调用 Builder } }2.1 Builder vs 子组件维度BuilderComponent子组件语法Builder function Foo() { ... }Component struct Foo { build() { ... } }状态共享父组件State独立State复用同组件内复用跨组件复用性能高不开新组件域中开新组件域适用页内分段HUD、菜单、遮罩独立功能块卡片、列表项实战经验页内分段用Builder跨页复用用Component。HUD 是游戏页独有分段用Builder最合适——共享State score不用Prop传。2.2 本项目所有 BuilderBuilder MainMenuView() { /* 主菜单 */ } Builder GameView() { /* 游戏页含棋盘、猫咪、HUD */ } Builder GameHUD() { /* 顶部 HUD */ } Builder PauseOverlay() { /* 暂停遮罩 */ } Builder GameOverView() { /* 结束页 */ } Builder StatItem(label: string, value: string) { /* 结束页统计项 */ }6 个 Builder 把 600 行的Index.ets拆成 6 个逻辑段build()里只需写if/else切 Builder——可读性倍增。本系列第 104 篇会专讲Builder。三、Row 三 Column 横排结构Row() { Column() { /* 左栏 */ }.layoutWeight(1) Column() { /* 中栏 */ }.layoutWeight(1) Column() { /* 右栏 */ }.layoutWeight(1) } .width(100%).padding({ left: 16, right: 16, top: 12, bottom: 12 })3.1 layoutWeight 按比例分宽Column().layoutWeight(1) // 占 1/(111) 1/3 Column().layoutWeight(2) // 占 2/(112) 1/2三栏 HUD 均用layoutWeight(1)——每栏 1/3 屏宽。如果左栏要更宽如得分数字长改layoutWeight(2)让它占 1/2。3.2 padding 内边距控 HUD 顶边.padding({ left: 16, right: 16, top: 12, bottom: 12 })左右 16HUD 内容不贴屏边。上下 12HUD 高度 内容 24薄薄一条不抢戏。3.3 backgroundColor 浅底浮起.backgroundColor(rgba(255,255,255,0.9))HUD 用 0.9 透明度白底比规则面板的 0.7 更不透——因为 HUD 是信息焦点要清晰可读不能让棋盘从下方透上来糊了文字。四、每栏 Column 的两行结构每栏是「标签 数值」两行 ColumnColumn() { Text(得分).fontSize(10).fontColor(#95A5A6) // 标签10 灰 Text(${this.score}).fontSize(20).fontColor(#2C3E50).fontWeight(FontWeight.Bold) // 数值20 深粗 }.alignItems(HorizontalAlign.Start)4.1 标签 vs 数值的字号对比元素fontSizefontColorfontWeight语义标签10#95A5A6灰Normal辅助说明数值20#2C3E50深Bold核心数据字号 10 vs 20——标签退到辅助位数值突出。这是 HUD 所有栏的通用层级。4.2 三栏对齐各异// 左栏Start数字左对齐 Column() { /* ... */ }.alignItems(HorizontalAlign.Start) // 中栏Center圆居中 Column() { /* ... */ }.alignItems(HorizontalAlign.Center) // 右栏End数字右对齐 Column() { /* ... */ }.alignItems(HorizontalAlign.End)关键设计三栏对齐不同但视觉平衡——左栏数字左靠、右栏数字右靠、中栏圆居中形成对称张力HUD 不偏。五、State 绑定实时刷新State score: number 0 State gameTime: number 0 Builder GameHUD() { Row() { Column() { Text(得分).fontSize(10).fontColor(#95A5A6) Text(${this.score}).fontSize(20).fontColor(#2C3E50).fontWeight(FontWeight.Bold) }.alignItems(HorizontalAlign.Start).layoutWeight(1) Column() { Text(时间).fontSize(10).fontColor(#95A5A6) Text(this.formatTime()).fontSize(20).fontColor(#2C3E50).fontWeight(FontWeight.Bold) }.alignItems(HorizontalAlign.End).layoutWeight(1) } }5.1 State 改变触发 HUD 重渲this.score 10 // 主循环里加分 → HUD 的得分数字自动刷新 this.gameTime 1 // 计时器递增 → HUD 的时间数字自动刷新ArkUI 监视机制State变量被重新赋值 → 所有读它的 UI含Builder内的Text重渲。HUD 自动跟随状态刷新不用手动调setText。5.2 模板字符串${this.score}的响应式Text(${this.score})模板字符串内读State也能触发响应——ArkUI 的依赖追踪能识别${this.score}中的this.score引用。5.3 formatTime 方法格式化formatTime(): string { const minutes Math.floor(this.gameTime / 60) const seconds this.gameTime % 60 return ${minutes.toString().padStart(2, 0)}:${seconds.toString().padStart(2, 0)} }gameTime是秒数formatTime()转成MM:SS字符串显示。格式化逻辑放方法里UI 只读方法返回值——分层清晰。六、Stack 层序让 HUD 悬浮顶层回到GameViewBuilder GameView() { Stack() { // 第 1 层棋盘背景 Column() { /* ... */ }.width(100%).height(100%).zIndex(0) // 第 2 层猫咪层 Column() { /* ... */ }.width(100%).height(100%).zIndex(1) // 第 3 层顶部 HUD GameHUD().zIndex(2) } .width(100%).height(100%) .alignContent(Alignment.Top) // HUD 顶部对齐 }6.1 HUD 在 Stack 顶部Stack的alignContent(Alignment.Top)让 HUD非齔满的子元素顶部居中对齐——HUD 悬在屏顶棋盘和猫咪层齔满在下方。6.2 HUD zIndex 必须最高GameHUD().zIndex(2) // 比棋盘 0、猫咪 1 都高如果不设 zIndex 或设低了猫咪下落到顶部时会盖住 HUD——玩家看不到得分。HUD 是常驻信息层必须最上。七、完整代码三栏 HUD 完整实现Entry Component struct Index { State gameState: GameState GameState.IDLE State score: number 0 State gameTime: number 0 // ... 其他 state Builder GameHUD() { Row() { // 左栏得分 Column() { Text(得分).fontSize(10).fontColor(#95A5A6) Text(${this.score}).fontSize(20).fontColor(#2C3E50).fontWeight(FontWeight.Bold) }.alignItems(HorizontalAlign.Start).layoutWeight(1) // 中栏预告区 Column() { Text(下一个).fontSize(10).fontColor(#95A5A6) Circle({ width: 24, height: 24 }).fillColor(#FFC107).margin({ top: 4 }) }.alignItems(HorizontalAlign.Center).layoutWeight(1) // 右栏时间 Column() { Text(时间).fontSize(10).fontColor(#95A5A6) Text(this.formatTime()).fontSize(20).fontColor(#2C3E50).fontWeight(FontWeight.Bold) }.alignItems(HorizontalAlign.End).layoutWeight(1) } .width(100%).padding({ left: 16, right: 16, top: 12, bottom: 12 }) .backgroundColor(rgba(255,255,255,0.9)) } formatTime(): string { const minutes Math.floor(this.gameTime / 60) const seconds this.gameTime % 60 return ${minutes.toString().padStart(2, 0)}:${seconds.toString().padStart(2, 0)} } Builder GameView() { Stack() { Column() { /* 棋盘 */ }.width(100%).height(100%).zIndex(0) Column() { /* 猫咪 */ }.width(100%).height(100%).zIndex(1) GameHUD().zIndex(2) } .width(100%).height(100%) .alignContent(Alignment.Top) } build() { Stack() { if (this.gameState GameState.PLAYING || this.gameState GameState.PAUSED) { GameView() } // ... 其他状态 } .width(100%).height(100%) } }八、调试技巧HUD 怎么调临时加 border给 HUD Row 和三栏 Column 都加.border({ width: 1, color: Color.Red })看清三栏边界。State刷新验证在aboutToAppear里临时setInterval(() { this.score 10 }, 1000)看 HUD 是否每秒刷新。zIndex 验层序HUD 被猫咪盖查 zIndex 是否最大。真机看对比HUD 0.9 透白底在预览器可能差异以真机为准。九、性能与最佳实践Builder比Component高效页内分段用Builder共享State不用传。layoutWeight比固定 width 响应式三栏均layoutWeight(1)屏宽变化自动均分。State绑定比手动 setText 高效ArkUI 自动追踪依赖不用手动调刷新。formatTime方法分离格式化逻辑别写在build()里放方法里build只读返回值。总结本篇我们从顶部 HUD 切入掌握Builder拆分、Row 三Column横排、layoutWeight均分、State绑定刷新、Stack层序五大要点并给出了三栏 HUD 完整代码。核心要点页内分段用 Builder三栏均分用 layoutWeight(1)State 自动刷新 HUDHUD zIndex 必须最顶。下一篇我们将继续游戏页拆解预告区的 Circle 圆形填充与 Row 组合。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源「猫猫大作战」项目源码本仓库entry/src/main/ets/pages/Index.etsBuilder 官方指南线性布局 (Row/Column) 官方指南状态管理概述 — HarmonyOS 官方文档Stack API 参考开源鸿蒙跨平台社区HarmonyOS 开发者官方文档首页系列索引本仓库articles/INDEX.md