在这里插入图片描述

一、应用概述

底部导航(Bottom Navigation)是一个模拟主流 App 底部 Tab 切换的演示应用。四个标签页(首页、发现、消息、我的)各自关联不同的页面内容,点击标签平滑切换内容区域。底部导航栏是移动应用中最常见的导航模式,iOS 的 UITabBar 和 Android 的 BottomNavigationView 都采用类似设计。

在 HarmonyOS 中,底部导航的实现没有使用专门的 TabBar 组件(虽然有 Tabs 组件),而是通过 Row + ForEach 手动构建导航栏,配合 @State 状态驱动内容切换。这种「造轮子」的方式反而让我们更深入地理解了状态驱动的本质。

二、技术架构

2.1 应用结构

┌─────────────────────────────────────┐
│  ‹ 返回           📱 底部导航        │
├─────────────────────────────────────┤
│                                     │
│            🏠 大图标                │
│                                     │
│   欢迎来到底部导航演示              │
│   这是首页的内容区域                │
│   可以放置各种信息和功能卡片        │
│                                     │
│                                     │
├─────────────────────────────────────┤
│  🏠      🔍      💬      👤       │  ← 底部导航栏
│  首页    发现    消息    我的       │
└─────────────────────────────────────┘

2.2 数据模型

interface TabItem {
  title: string;   // 标签名称
  icon: string;    // emoji 图标
  content: string; // 页面内容(含换行符)
  color: string;   // 标签主题色(选中时使用)
}

2.3 状态变量

变量 类型 用途
currentTab number 当前选中的标签索引(0-3)
tabs TabItem[] 4 个标签的配置数据

三、核心代码深度解析

3.1 状态驱动的 Tab 切换

@State currentTab: number = 0;

仅用一个 number 类型的 @State 变量就驱动了整个页面的切换。这个数字既是底部导航栏的选中索引,也是内容区域的显示索引。

内容区域

Column() {
  Text(this.tabs[this.currentTab].icon).fontSize(64).margin({ bottom: 16 })
  Text(this.tabs[this.currentTab].content)
    .fontSize(16).fontColor('#555').lineHeight(28).textAlign(TextAlign.Center)
}
.layoutWeight(1).justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)

通过 this.currentTab 索引 tabs 数组,动态获取当前标签的 icon、content 和 color。这是 ArkUI 中「数据驱动 UI」最直接的体现——只需更新 currentTab,所有相关 UI 自动刷新。

3.2 底部导航栏

Row() {
  ForEach(this.tabs, (tab: TabItem, idx: number) => {
    Column() {
      Text(tab.icon).fontSize(22)
        .opacity(this.currentTab === idx ? 1 : 0.5)
      Text(tab.title).fontSize(11)
        .fontColor(this.currentTab === idx ? tab.color : '#999')
        .fontWeight(this.currentTab === idx ? FontWeight.Medium : FontWeight.Regular)
    }
    .layoutWeight(1)
    .padding({ top: 6, bottom: 6 })
    .onClick(() => { this.currentTab = idx })
  })
}
.width('100%').height(64)
.backgroundColor('#fff')
.borderRadius({ topLeft: 16, topRight: 16 })
.shadow({ radius: 8, color: '#20000000', offsetY: -2 })

导航栏的样式设计

属性 说明
高度 64 标准导航栏高度,符合人体工学
背景色 #fff 纯白背景
圆角 { topLeft: 16, topRight: 16 } 仅顶部圆角,与底部边缘平滑过渡
阴影 offsetY: -2 向上偏移,产生「浮在内容之上」的效果

选中/未选中状态对比

样式属性 未选中 选中
图标透明度 0.5 1.0
文字颜色 #999(灰色) tab.color(主题色)
文字字重 Regular Medium

这种「透明度+颜色+字重」的三重区分确保了选中状态的清晰可辨,同时保持了整体视觉的协调性。

3.3 圆角与阴影的巧妙运用

.borderRadius({ topLeft: 16, topRight: 16 })
.shadow({ radius: 8, color: '#20000000', offsetY: -2 })

borderRadius 对象语法:ArkUI 支持为四个角分别设置圆角半径,格式为 { topLeft, topRight, bottomLeft, bottomRight }。这里只设定了顶部两个角的圆角,底部紧贴屏幕边缘,形成悬浮导航栏的效果。

阴影向上偏移offsetY: -2 表示阴影向上偏移 2vp,配合 radius: 8(较大的模糊半径),产生导航栏「浮在内容上方」的视觉效果。这与 Material Design 的 Bottom App Bar 设计语言一致。

四、HarmonyOS 特色功能深度解析

4.1 layoutWeight 弹性布局

.layoutWeight(1)

每个 Tab 项都设置 layoutWeight(1),在 Row 容器中等分宽度。无论屏幕宽度是 360vp 还是 428vp,四个 Tab 自动平分底部空间。

layoutWeight 的计算规则

  1. 先分配所有未设置 layoutWeight 的组件的固定宽度
  2. 剩余空间按 layoutWeight 值比例分配给设置了该属性的组件
  3. 如果所有子组件都设置了 layoutWeight(1),则等分总宽度

4.2 ForEach 的索引参数

ForEach(this.tabs, (tab: TabItem, idx: number) => {
  // idx 就是当前项的索引
  .onClick(() => { this.currentTab = idx })
})

ForEach 的回调函数可以接收两个参数:

  1. 第一个参数:数组中的元素值
  2. 第二个参数:元素在数组中的索引(从 0 开始)

使用索引参数可以避免为每个 Tab 手动绑定 onClick 事件,这是 ForEach 简化代码的重要特性。

4.3 Text 组件的多行内容

content: '欢迎来到底部导航演示\n\n这是首页的内容区域\n可以放置各种信息和功能卡片'

Text 组件中使用 \n 换行符可以实现多行文本显示,配合 lineHeight 属性控制行间距。这是最简单的内容换行方式,不需要使用多个 Text 组件堆叠。

五、UI/UX 设计分析

5.1 四标签导航

四个标签覆盖了主流 App 的标准导航结构:

标签 图标 主题色 典型用途
首页 🏠 #0077FF 蓝色 内容信息流
发现 🔍 #4CAF50 绿色 搜索/探索
消息 💬 #FF9800 橙色 通知/聊天
我的 👤 #9C27B0 紫色 个人中心

色彩心理学:四种主题色分别代表不同的功能属性——蓝色专业、绿色自然、橙色活跃、紫色创意。

5.2 沉浸式导航栏设计

底部导航栏的设计借鉴了现代移动操作系统的设计语言:

  1. 悬浮效果:白色背景 + 顶部圆角 + 向上阴影,模拟物理悬浮
  2. 触控热区padding({ top: 6, bottom: 6 }) 确保每个 Tab 的点击区域足够大(至少 44vp 的触控高度)
  3. 视觉权重:图标 22px > 文字 11px,图标视觉权重更大,易于识别

5.3 内容区域设计

内容区域居中显示大图标和欢迎文字:

  • 图标 fontSize(64):大尺寸图标形成视觉焦点
  • 文字 lineHeight(28):舒适的阅读行距
  • textAlign(TextAlign.Center):居中排列

六、最佳实践与优化建议

6.1 当前代码亮点

  1. 极简状态管理:仅用 currentTab 一个变量完成全部切换逻辑
  2. 数据驱动 UI:所有显示内容来自 tabs 数组,新增标签只需修改数据
  3. 导航栏悬浮设计:圆角 + 阴影营造沉浸视觉体验
  4. Tab 等分布局layoutWeight(1) 实现自适应宽度

6.2 可优化方向

// 优化建议 1:页面切换动画
// 使用 transition 添加页面切换动画
Column()
  .transition({ type: TransitionType.Insert, translate: { x: 100 } })
  .transition({ type: TransitionType.Delete, translate: { x: -100 } })

// 优化建议 2:使用 Tabs 组件替代手动构建
// HarmonyOS 提供了 Tabs + TabContent 原生组件
Tabs() {
  TabContent() { /* 首页内容 */ }.tabBar('🏠 首页')
  TabContent() { /* 发现内容 */ }.tabBar('🔍 发现')
  TabContent() { /* 消息内容 */ }.tabBar('💬 消息')
  TabContent() { /* 我的内容 */ }.tabBar('👤 我的')
}
.barPosition(BarPosition.End)  // 导航栏在底部

// 优化建议 3:角标通知
// 在 Tab 图标上显示未读数量
Stack() {
  Text(tab.icon).fontSize(22)
  if (unreadCount > 0) {
    Text(unreadCount > 99 ? '99+' : unreadCount.toString())
      .fontSize(10).fontColor('#fff')
      .backgroundColor('#F44336').borderRadius(8)
      .padding({ left: 4, right: 4 }).height(16)
      .align(Alignment.TopEnd)
  }
}

// 优化建议 4:页面缓存
// 使用 @State 保存每个 Tab 的滚动位置
@State scrollPositions: number[] = [0, 0, 0, 0];

// 优化建议 5:导航栏隐藏/显示
// 根据内容滚动方向自动隐藏/显示导航栏
@State navBarVisible: boolean = true;

6.3 性能优化

  • Tab 数量控制:底部导航建议不超过 5 个 Tab(Material Design 规范),超过时需使用「更多」折叠或滚动模式
  • 内容懒加载:当前实现中 4 个 Tab 的内容同时存在(通过 currentTab 控制显示),对于内容较重的页面应使用懒加载
  • 图标性能:使用 emoji 而非图片图标,减少资源加载开销

七、总结与扩展

底部导航应用展示了 ArkUI 中实现 Tab 导航的核心模式:

知识点 应用位置 重要程度
@State 状态驱动 currentTab 切换 ★★★★★
layoutWeight 弹性布局 Tab 等分 ★★★★★
ForEach 索引参数 onClick 事件绑定 ★★★★☆
borderRadius 对象语法 导航栏圆角 ★★★☆☆
shadow 阴影 悬浮效果 ★★★☆☆

扩展思路

  1. 与 Tabs 组件对比:学习 HarmonyOS 原生 Tabs 组件的 API,了解手动构建与原生组件的权衡
  2. 中间大按钮:部分 App 在底部导航栏中间放置大按钮(如发帖按钮),可通过 Stack 布局实现
  3. 导航栏颜色跟随:根据所在 Tab 的主题色改变导航栏颜色
  4. 返回拦截:配合 onBackPress 实现双击退出或确认提示
  5. 跨页面状态保持:使用 AppStorage 在页面切换时保持 Tab 状态
  6. 手势切换:添加左右滑动手势(SwipeGesture)切换 Tab

底部导航是现代移动应用的标准导航模式。通过这个案例,你不仅学会了如何构建底部导航栏,更理解了状态驱动的本质——一个数字的变化驱动整个页面的重新渲染。这就是声明式 UI 的核心思想:UI 是状态的函数

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐