HarmonyOS ArkTS 底部导航栏实现详解:从零到一的完整指南_鸿蒙arkts 底部菜单栏
文章目录
前言
在移动应用开发中,底部导航栏是用户界面中最重要的组件之一。它不仅提供了应用的主要功能入口,还直接影响着用户体验。本文将深入分析基于 HarmonyOS ArkTS 框架实现的底部导航栏,通过实际代码案例,带您掌握从数据结构设计到最终实现的完整流程。
一、项目背景与需求分析
1.1 应用场景
这是一个医疗相关的应用,包含四个主要功能模块:
- 医院:医院信息展示
- 科室:科室分类管理
- 医生:医生信息查询
- 我的:个人中心
1.2 技术选型
- 框架:HarmonyOS ArkTS
- 语言:TypeScript/ArkTS
- UI组件:Tabs + TabContent
- 状态管理:@State 装饰器
二、核心数据结构设计
2.1 接口定义
interface tabBarInfo { title: string, // 导航项标题 normalImg: ResourceStr, // 默认状态图标 selectedImg: ResourceStr // 选中状态图标}
设计亮点:
- 使用 TypeScript 接口确保类型安全
- 支持双状态图标(正常/选中)
- 资源引用使用
ResourceStr
类型,符合 HarmonyOS 规范
2.2 数据初始化
tabs: tabBarInfo[] = [ { \'title\': \'医院\', \'normalImg\': $r(\'app.media.hospital\'), \'selectedImg\': $r(\"app.media.hospital_active\") }, { \'title\': \'科室\', \'normalImg\': $r(\'app.media.department\'), \'selectedImg\': $r(\"app.media.department_active\") }, { \'title\': \'医生\', \'normalImg\': $r(\'app.media.doctor\'), \'selectedImg\': $r(\"app.media.doctor_active\") }, { \'title\': \'我的\', \'normalImg\': $r(\'app.media.profile\'), \'selectedImg\': $r(\"app.media.profile_active\") }]
技术要点:
- 使用 $r() 函数引用应用资源
- 资源命名规范:模块名_active 表示激活状态
- 数组结构便于后续的 ForEach 遍历
三、状态管理实现
3.1 状态变量
@State currentIndex: number = 0
关键特性:
@State
装饰器实现响应式状态管理- 默认选中第一个标签页
- 状态变化自动触发UI更新
3.2 状态更新机制
.onSelected((index: number) => { this.currentIndex = index})
实现原理:
- 听 Tabs 组件的
onSelected
事件 - 实时更新
currentIndex
状态 - 状态变化自动触发
tabBuilder
重新渲染
四、自定义组件构建
4.1 @Builder 装饰器
@BuildertabBuilder(item: tabBarInfo, index: number) { Column() { Image(this.currentIndex === index ? item.selectedImg : item.normalImg) .size({ width: 25, height: 25 }) Text(item.title) .fontColor(this.currentIndex === index ? \'#007AFF\' : \'#6B6B6B\') .margin({ top: 3 }) }}
技术亮点:
@Builder
装饰器创建可复用的UI组件- 条件渲染实现图标状态切换
- 动态颜色变化增强视觉反馈
五、主界面布局实现
5.1 Tabs 组件配置
Tabs({ barPosition: BarPosition.End }) { ForEach(this.tabs, (item: tabBarInfo, index: number) => { TabContent() { Text(item.title).fontSize(30) } .tabBar(this.tabBuilder(item, index)) })}
核心配置:
- barPosition: BarPosition.End:底部定位
- ForEach 循环渲染标签页内容
- tabBar() 绑定自定义的标签栏样式
六、整体代码实现过程
Index.ets
文件
//约定底部导航栏数据结构interface tabBarInfo { title: string, //标题 normalImg: ResourceStr, //默认图标 selectedImg: ResourceStr, //选中的图片}@Entry@Componentstruct Index { tabs: tabBarInfo[] = [ { \'title\': \'医院\', \'normalImg\': $r(\'app.media.hospital\'), \'selectedImg\': $r(\"app.media.hospital_active\") }, { \'title\': \'科室\', \'normalImg\': $r(\'app.media.department\'), \'selectedImg\': $r(\"app.media.department_active\") }, { \'title\': \'医生\', \'normalImg\': $r(\'app.media.doctor\'), \'selectedImg\': $r(\"app.media.doctor_active\") }, { \'title\': \'我的\', \'normalImg\': $r(\'app.media.profile\'), \'selectedImg\': $r(\"app.media.profile_active\") }] //默认第一个选中 @State currentIndex: number = 0 //自定义tabBuilder函数组件 @Builder tabBuilder(item: tabBarInfo, index: number) { Column() { Image(this.currentIndex === index ? item.selectedImg : item.normalImg) .size({ width: 25, height: 25 }) Text(item.title) .fontColor(this.currentIndex === index ? \'#007AFF\' : \'#6B6B6B\') .margin({ top: 3 }) } } build() { Column() { Tabs({ barPosition: BarPosition.End }) { ForEach(this.tabs, (item: tabBarInfo, index: number) => { TabContent() { Text(item.title).fontSize(30) } .tabBar(this.tabBuilder(item, index)) }) } //设置页面不需要左右滑动切换,只点击tab切换 .scrollable(false) //点击tab监听事件 .onSelected((index: number) => { this.currentIndex = index }) } .height(\'100%\') //设置背景色 .backgroundColor(0xf4f4f5) //设置沉浸式页面 //官方文档:https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-immersive#section1052895593418 .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) }}
七、运行效果截图
八、官方文档
- 沉浸式页面实现:https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-immersive#section1052895593418
- 选项卡 (Tabs):https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-navigation-tabs