HarmonyOS NEXT 企业级记账APP:实现底部 Tab 导航
实现底部 Tab 导航本文是《HarmonyOS NEXT 企业级开发实战30篇打造智能记账APP》系列的第04篇对应 Git Tagv0.0.4。承接第 03 篇的主题系统本篇使用 ArkUI 的 Tabs 组件搭建首页、统计、预算、我的四个底导航 Tab并封装 AppTabBar 通用组件。前言底导航 Tab 是移动应用的核心导航模式用户 80% 的操作都从底导航发起。HarmonyLedger 规划四个主 Tab首页、统计、预算、我的。ArkUI 提供原生Tabs组件支持底导航但企业级项目需要封装统一的 AppTabBar 组件便于后续扩展与主题适配。本文将带你使用 ArkUI Tabs 组件搭建底导航框架封装 AppTabBar 通用组件支持图标、文字、主题色实现四个 Tab 页面占位与切换动效集成主题系统响应深色模式企业级核心原则底导航必须封装复用、禁止重复、支持主题。参考 ArkUI Tabs 组件 了解官方约定。一、Tab 规划1.1 四个主 TabHarmonyLedger 选用最经典的四 Tab布局覆盖核心业务场景Tab 序号名称图标页面业务0首页homeHomeView账单汇总、快捷新增1统计chartStatisticsView收支图表分析2预算budgetBudgetView预算设置与进度3我的userProfileView设置、关于1.2 Tab 命名规范Tab 命名规范 - 英文小写下划线home / chart / budget / user - 中文展示用首页 / 统计 / 预算 / 我的 - 图标资源icon_tab_{name}.png - 路由页面{Name}View.ets大驼峰 - 资源字符串tab_{name}_label设计要点Tab 命名一旦确定禁止修改否则会牵动图标、路由、字符串多处资源。二、Tabs 组件基础2.1 Tabs 与 TabContentArkUI 原生 Tabs 组件使用方式Entry Component struct MainView { State currentIndex: number 0; build() { Tabs({ index: this.currentIndex }) { TabContent() { HomeView() } .tabBar({ text: 首页, icon: $r(app.media.icon_tab_home) }) TabContent() { StatisticsView() } .tabBar({ text: 统计, icon: $r(app.media.icon_tab_chart) }) TabContent() { BudgetView() } .tabBar({ text: 预算, icon: $r(app.media.icon_tab_budget) }) TabContent() { ProfileView() } .tabBar({ text: 我的, icon: $r(app.media.icon_tab_user) }) } .barPosition(BarPosition.End) .onChange((index: number) { this.currentIndex index; }) } }2.2 关键属性属性说明值barPositionTab 位置BarPosition.End底导航/Start顶导航vertical是否纵向false默认横向scrollable可滚动false四 Tab 不需滚动onChange切换回调(index: number) voidtabBarTab 标签配置{ text, icon }踩坑点TabContent不能直接传 builder 参数必须用.tabBar(...)设置标签。这是鸿蒙 ArkUI 的强制约束。三、封装 AppTabBar3.1 组件设计目标企业级底导航需要满足图标文字双显示未选中态灰色、选中态主题色响应深色模式颜色自动切换Badge 角标支持消息提醒可配置Tab 数量与内容3.2 TabConfig 数据模型// model/TabConfig.ets export class TabConfig { name: string; // home / chart / budget / user label: string; // 显示文字 icon: Resource; // 图标资源 badge?: number 0; // 角标数字0 不显示 constructor(name: string, label: string, icon: Resource, badge?: number) { this.name name; this.label label; this.icon icon; this.badge badge ?? 0; } }3.3 AppTabBar 组件实现// components/navigation/AppTabBar.ets import { TabConfig } from ../../model/TabConfig; import { AppColors } from ../../theme/Colors; import { AppFontSize } from ../../theme/Typography; import { AppSpace } from ../../theme/Spacing; Component export struct AppTabBar { Prop tabs: TabConfig[] []; Prop currentIndex: number 0; BuilderParam onTabClick: (index: number) void; build() { Row() { ForEach(this.tabs, (tab: TabConfig, index: number) { Column() { Image(tab.icon) .width(24) .height(24) .fillColor(this.currentIndex index ? AppColors.Budget : AppColors.SecondaryText) Text(tab.label) .fontSize(AppFontSize.XS) .fontColor(this.currentIndex index ? AppColors.Budget : AppColors.SecondaryText) .margin({ top: AppSpace.XS }) // Badge 角标 if (tab.badge 0) { Text(tab.badge.toString()) .fontSize(10) .fontColor(#FFFFFF) .backgroundColor(AppColors.Expense) .borderRadius(8) .padding(2) .position({ x: 24, y: -4 }) } } .layoutWeight(1) .justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Center) .onClick(() { this.onTabClick(index); }) }, (tab: TabConfig) tab.name) } .width(100%) .height(56) .backgroundColor(AppColors.CardBackground) .border({ width: { top: 1 }, color: AppColors.Separator }) } }关键技术BuilderParam用于将点击回调暴露给父组件这是 ArkUI V1 组件通信的标准方案。四、四个 Tab 页面占位4.1 HomeView 占位// pages/HomeView.ets Entry Component struct HomeView { build() { Column() { Text(首页) .fontSize(24) .fontWeight(FontWeight.Bold) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }4.2 StatisticsView 占位// pages/StatisticsView.ets Entry Component struct StatisticsView { build() { Column() { Text(统计分析) .fontSize(24) .fontWeight(FontWeight.Bold) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }4.3 BudgetView 与 ProfileView// pages/BudgetView.ets Entry Component struct BudgetView { build() { Column() { Text(预算中心) .fontSize(24) .fontWeight(FontWeight.Bold) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } } // pages/ProfileView.ets Entry Component struct ProfileView { build() { Column() { Text(我的) .fontSize(24) .fontWeight(FontWeight.Bold) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }五、主页面集成5.1 MainView 集成 Tabs// pages/MainView.ets import { AppTabBar } from ../components/navigation/AppTabBar; import { TabConfig } from ../model/TabConfig; import { HomeView } from ./HomeView; import { StatisticsView } from ./StatisticsView; import { BudgetView } from ./BudgetView; import { ProfileView } from ./ProfileView; Entry Component struct MainView { State currentIndex: number 0; State tabs: TabConfig[] [ new TabConfig(home, 首页, $r(app.media.icon_tab_home)), new TabConfig(chart, 统计, $r(app.media.icon_tab_chart)), new TabConfig(budget, 预算, $r(app.media.icon_tab_budget)), new TabConfig(user, 我的, $r(app.media.icon_tab_user)) ]; build() { Stack({ alignContent: Alignment.TopStart }) { // 内容区 Column() { if (this.currentIndex 0) { HomeView() } else if (this.currentIndex 1) { StatisticsView() } else if (this.currentIndex 2) { BudgetView() } else { ProfileView() } } .width(100%) .height(100%) .padding({ bottom: 56 }) // 底导航 AppTabBar({ tabs: this.tabs, currentIndex: this.currentIndex, onTabClick: (index: number) { this.currentIndex index; } }) } .width(100%) .height(100%) } }5.2 路由配置更新// entry/src/main/resources/base/profile/main_pages.json { src: [ pages/MainView, // 主入口改为 MainView pages/HomeView, pages/StatisticsView, pages/BudgetView, pages/ProfileView ] }// EntryAbility.ets 入口改为 MainView windowStage.loadContent(pages/MainView, (err) { ... });架构调整入口从 HomeView 改为 MainView底导航由 MainView 持有四个 Tab 页面作为子组件。这是鸿蒙多 Tab 应用的标准结构。六、图标资源准备6.1 Tab 图标规格项规格尺寸24x24 dp格式PNG带 alpha 通道或 SVG色彩单色通过 fillColor 染色命名icon_tab_{name}.png6.2 资源放置entry/src/main/resources/base/media/ ├─ icon_tab_home.png ├─ icon_tab_chart.png ├─ icon_tab_budget.png └─ icon_tab_user.png统一染色方案图标统一用白色 PNG通过Image.fillColor()动态染色。这样未选中态、选中态、深色模式都能复用同一张图。七、最佳实践7.1 Tab 切换性能优化// ❌ 错误每次切换都重建所有 Tab 页面 Tabs() { TabContent() { HomeView() } TabContent() { StatisticsView() } // 切换到统计时HomeView 仍在后台占用内存 } // ✅ 正解用 if 懒加载 Stack() { if (this.currentIndex 0) { HomeView() } else if (this.currentIndex 1) { StatisticsView() } }7.2 Tab 状态保持如果希望 Tab 切换时保留各页面状态State homeState: HomeState new HomeState(); State statsState: StatsState new StatsState(); // 用 Stack 叇叠所有页面通过 visibility 控制 Stack() { HomeView({ state: this.homeState }).visibility(this.currentIndex 0 ? Visibility.Visible : Visibility.Hidden) StatisticsView({ state: this.statsState }).visibility(this.currentIndex 1 ? Visibility.Visible : Visibility.Hidden) }权衡状态保持会占用更多内存HarmonyLedger 暂不启用后续 v0.2.7 性能优化篇再讨论。八、运行验证8.1 编译检查hvigorw assembleHap--modemodule-pproductdefault8.2 运行验证应用启动后显示首页底导航四个 Tab 均可见点击统计 Tab切换到统计分析页选中态 Tab 文字和图标变蓝色AppColors.Budget未选中态 Tab 灰色深色模式下同步切换九、常见问题9.1 TabContent 传参错误错误原因解决TabContent(builder)不渲染不能传 builder 对象用TabContent() { ... }包裹内容图标不显示资源路径错误检查$r(app.media.icon_tab_xxx)名是否一致9.2 切换闪烁// 原因if 切换会销毁重建页面 // 解决用 visibility 保留所有页面 .visibility(currentIndex index ? Visibility.Visible : Visibility.Hidden)9.3 底部遮挡// 内容区需预留底导航高度 Column() { ... } .padding({ bottom: 56 }) // 与 AppTabBar.height 一致十、Git 提交10.1 Commit Messagegitadd.gitcommit-mfeat(navigation): 实现底部 Tab 导航与 AppTabBar 封装 - 新增 AppTabBar 通用底导航组件 - 新增 TabConfig 数据模型 - 创建 HomeView/StatisticsView/BudgetView/ProfileView 占位页 - 集成 MainView 持有 Tabs 切换 - 更新 EntryAbility 入口为 MainView - 添加四个 Tab 图标资源10.2 CHANGELOG## [v0.0.4] - 2026-07-27 ### Added - components/navigation/AppTabBar.ets通用底导航组件 - model/TabConfig.etsTab 配置数据模型 - pages/MainView.ets主页面持有 Tabs - pages/StatisticsView.ets、BudgetView.ets、ProfileView.ets占位页 - 资源icon_tab_home/chart/budget/user.png ### Changed - EntryAbility 入口改为 MainView - main_pages.json 增加 MainView 路由附录运行效果截图上图展示了本模块的完整运行效果。实际项目中可使用 DevEco Studio 模拟器或真机截图替换此占位图。总结本文完整介绍了 HarmonyLedger底部 Tab 导航的实现包含原生 Tabs 用法、AppTabBar 组件封装、四个 Tab 页面占位、主页面集成。通过本篇你可以使用 ArkUI Tabs 组件搭建底导航封装可复用的 AppTabBar 组件支持图标文字角标实现主题色响应选中态与深色模式理解 EntryAbility 与 MainView 的入口关系下一篇预告《首页布局与 SummaryCard 设计》将开发首页核心 UI今日支出、今日收入、最近账单列表并封装 SummaryCard 汇总卡片组件。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源本篇源码GitHub Tag v0.0.4ArkUI Tabs 文档tabsArkUI Image 组件imageTabContent APItabcontentArkUI 组件通信component-communicationBarPosition 枚举barposition鸿蒙图标资源规范icon-resources

相关新闻

混合云架构下网络互通方案设计

混合云架构下网络互通方案设计

混合云架构下网络互通方案设计随着企业数字化转型的深入,混合云凭借其兼顾公有云弹性灵活与私有云安全可控的独特优势,已成为主流IT架构选择。然而,混合云的核心价值在于“混合”,即公有云与私有云、边缘节点乃至多云环境之间能否…

2026/9/25 2:36:16 阅读更多 →
嵌入式领域AI4SE详解:AI赋能软件工程的实践与展望

嵌入式领域AI4SE详解:AI赋能软件工程的实践与展望

1. 引言:嵌入式软件开发的挑战与AI机遇嵌入式系统作为现代工业、汽车、医疗和消费电子的核心,其软件开发面临着独特的挑战:资源受限(内存、算力)、实时性要求高、安全性与可靠性至关重要、软硬件耦合紧密、开发周期长且…

2026/9/23 23:21:01 阅读更多 →
AcWing 多重背包问题I

AcWing 多重背包问题I

问题如下: 有 N种物品和一个容量是 V的背包。 第 i 种物品最多有 si件,每件体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。 输出最大价值。 输入格式 第一行两个整数…

2026/9/23 23:56:51 阅读更多 →

最新新闻

Moto CodeBuild 模拟实战:在测试中 Mock AWS CodeBuild 项目与构建 API

Moto CodeBuild 模拟实战:在测试中 Mock AWS CodeBuild 项目与构建 API

Mock测试 【免费下载链接】moto A library that allows you to easily mock out tests based on AWS infrastructure. 项目地址: https://gitcode.com/gh_mirrors/mo/moto 点击查看 免费下载 本篇技术指南围绕 moto 仓库中 CodeBuild 服务文档 展开,系统…

2026/9/25 3:31:50 阅读更多 →
并行加法器 vs 先行进位加法器:进位延迟、关键路径与工程实现

并行加法器 vs 先行进位加法器:进位延迟、关键路径与工程实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 3:31:50 阅读更多 →
grammars-v4 中 R 语言 ANTLR 语法解析指南:掌握 RFilter 换行符预处理机制

grammars-v4 中 R 语言 ANTLR 语法解析指南:掌握 RFilter 换行符预处理机制

编程语言编译器开发工具 【免费下载链接】grammars-v4 Grammars written for ANTLR v4; expectation that the grammars are free of actions. 项目地址: https://gitcode.com/gh_mirrors/gr/grammars-v4 点击查看 免费下载 导读 在 grammars-v4 仓库的 r 目录下&…

2026/9/25 3:31:50 阅读更多 →
VoltAgent 接入 Deep Infra:使用 `deepinfra/<model>` 模型路由打通低成本高性能推理

VoltAgent 接入 Deep Infra:使用 `deepinfra/<model>` 模型路由打通低成本高性能推理

人工智能AI AgentAgent 框架后端多智能体RAG工具调用Agent 记忆 【免费下载链接】voltagent AI Agent Engineering Platform built on an Open Source TypeScript AI Agent Framework 项目地址: https://gitcode.com/gh_mirrors/vo/voltagent 点击查看 免费下载 De…

2026/9/25 3:31:50 阅读更多 →
用 ANTLR v4 解析 Scala 3:grammars-v4 中 Scala3 语法的设计、覆盖率与已知限制

用 ANTLR v4 解析 Scala 3:grammars-v4 中 Scala3 语法的设计、覆盖率与已知限制

编程语言编译器开发工具 【免费下载链接】grammars-v4 Grammars written for ANTLR v4; expectation that the grammars are free of actions. 项目地址: https://gitcode.com/gh_mirrors/gr/grammars-v4 点击查看 免费下载 本文面向需要为 Scala 3 构建词法/语法分…

2026/9/25 3:31:50 阅读更多 →
Java工业物联网IOT驱动包:统一Modbus-TCP、Bacnet与OPC-UA协议接入

Java工业物联网IOT驱动包:统一Modbus-TCP、Bacnet与OPC-UA协议接入

简介:这份基于Java的物联网IOT通用驱动包设计源码,面向中高级Java开发者与系统集成商,解决Modbus-TCP、Bacnet、OPC-UA等多协议设备接入问题,封装为SDK形式,可直接嵌入业务系统。压缩包共76个文件,约1.73MB…

2026/9/25 3:30:49 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →