在这里插入图片描述

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

案例概述

本案例展示如何通过 BottomNavigationBar 构建一个三页面切换的底部导航结构,模拟常见的「首页 / 消息 / 我的」应用框架。在移动端,这是一种非常普遍的导航方式;在 PC 端,也可以作为与移动端保持一致体验的一种选择。

页面结构:

  • 使用 StatefulWidget 管理当前选中的导航索引;
  • 根据索引从一个页面列表中选择要展示的内容;
  • 通过 BottomNavigationBar 提供三个底部导航项,点击时更新索引;
  • 根据屏幕宽度决定 AppBar 标题是否居中。

核心概念

1. 状态与页面切换

底部导航的本质是一个“索引切换”的问题:

  • 使用一个整型变量 _currentIndex 表示当前选中项;
  • 准备一个 Widget 列表 _pages,索引与导航项一一对应;
  • 当用户点击底部导航某一项时,更新 _currentIndex 并触发重建;
  • build 方法中通过 _pages[_currentIndex] 获取当前要显示的页面。

2. BottomNavigationBarItem

每个导航项由 BottomNavigationBarItem 描述:

  • icon: 导航图标;
  • label: 文字说明;
  • 可以根据平台主题自动处理选中/未选中颜色与样式。

代码详解

1. StatefulWidget 与页面列表

class BottomNavPage extends StatefulWidget {
  const BottomNavPage({Key? key}) : super(key: key);

  
  State<BottomNavPage> createState() => _BottomNavPageState();
}

class _BottomNavPageState extends State<BottomNavPage> {
  int _currentIndex = 0;

  static const _pages = [
    Center(child: Text('首页内容')),
    Center(child: Text('消息内容')),
    Center(child: Text('我的内容')),
  ];
  // ...
}

说明:

  • 使用 StatefulWidget 是因为 _currentIndex 会根据用户操作发生变化;
  • _pages 使用 static const,表示这些页面本身是静态不变的小部件树;
  • 实际项目中,你可以将这些占位 Center 替换为真正的首页、消息页、个人中心页面。

2. Scaffold 与 AppBar


Widget build(BuildContext context) {
  final screenWidth = MediaQuery.of(context).size.width;
  final isPC = screenWidth >= 1200;

  return Scaffold(
    appBar: AppBar(
      title: const Text('案例10:底部导航 - BottomNavigationBar'),
      centerTitle: isPC,
      elevation: 2,
    ),
    body: _pages[_currentIndex],
    bottomNavigationBar: BottomNavigationBar(
      currentIndex: _currentIndex,
      onTap: (index) {
        setState(() {
          _currentIndex = index;
        });
      },
      items: const [
        BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
        BottomNavigationBarItem(icon: Icon(Icons.message), label: '消息'),
        BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
      ],
    ),
  );
}

说明:

  • body 显示当前索引对应的页面内容;
  • BottomNavigationBar.currentIndex_currentIndex 同步;
  • onTap 回调中调用 setState 更新索引,驱动 UI 刷新;
  • 通过 centerTitle: isPC 在 PC 端让标题居中,统一视觉风格。

OpenHarmony PC 端适配要点

  1. 导航模式选择

    • 在桌面应用中,底部导航并不是唯一选项,也可以改用左侧垂直导航栏或顶部标签页;
    • 在跨端场景中,沿用移动端的底部导航可以降低学习成本,让用户在不同设备上保持一致的操作习惯。
  2. 窗口大小变化与布局

    • 当窗口高度较小(例如窄高窗口)时,底部导航仍然会占据一行高度,需要注意主内容的可见区域;
    • 在极端宽屏或多窗口场景下,可以考虑改变导航布局,例如在 PC 模式下将导航移到左侧。
  3. 鼠标与键盘交互

    • 底部导航默认支持鼠标点击;
    • 可以在后续扩展中加入键盘快捷键,例如数字键 1/2/3 快速切换页面。

扩展建议

  • 为每个导航项对应的页面增加 AppBar 操作按钮或浮动操作按钮;
  • 根据当前选中的 Tab 调整整体主题色或背景,强化模块区分感;
  • 在“消息”页面增加未读消息角标,通过 BottomNavigationBarItembadge 或自定义小部件实现;
  • 结合路由管理(如 Navigator 或第三方路由库),实现底部导航与深度链接、返回栈的配合。

更深入的概念说明(设计层面)

1. 底部导航适合什么样的信息架构?

从信息架构(IA)的角度看,底部导航最适合用于承载数量有限、层级相同的顶级模块,通常在 3–5 个之间,例如:

  • 首页:信息聚合、推荐流、全局入口;
  • 消息 / 通知:与用户直接相关的动态和提醒;
  • 个人中心 / 我的:账户信息、设置、个人资产等。

如果某个模块只是一个功能入口或工具页,而不是信息架构中的“一级板块”,就不适合放到底部导航中,否则会让结构变得混乱。此时更合适的做法是:

  • 将其放在首页的某个卡片或按钮内,由首页跳转;
  • 或者集成在个人中心 / 设置页中。

2. 与其他导航方式的对比

在多端场景下,你通常会同时面对几种常见导航结构:

  • 底部导航(BottomNavigationBar)

    • 优点:在移动端占据固定区域,随时可见;用户对这种模式已经非常熟悉;
    • 缺点:在 PC 宽屏上可用空间相对分散,有时会显得“离主体内容较远”。
  • 顶部标签页(TabBar + TabBarView)

    • 优点:更贴近浏览器、多文档界面的使用习惯,适合内容强相关的几个视图切换(如列表 / 图表 / 概览);
    • 缺点:当模块之间差异较大、信息结构层级复杂时,不如底部导航直观。
  • 侧边导航(Drawer / 固定侧边栏)

    • 优点:适合 PC 端和大屏设备,可以展示更多层级(带分组、折叠的菜单树);
    • 缺点:在小屏设备上会占据较多水平空间,需要折叠或改为抽屉。

因此,底部导航更适合作为“少量顶级模块的入口”,而不是承载完整的菜单树。对于更复杂的后台管理系统或多层级结构,通常会在 PC 端改用侧边导航或顶部菜单,将底部导航仅用于移动端。

3. 多端一致性与差异化

在 OpenHarmony 这类多端平台下,一个常见的设计问题是:

是否要在 PC 端也保留底部导航?

没有绝对答案,可以从以下几个角度考虑:

  • 一致性优先

    • 如果你的应用主要用户来自移动端,希望“换到 PC 也不用重新学习”,保留底部导航是一种不错的选择;
    • PC 端可以再额外提供快捷方式(比如顶部菜单、快捷键),但不一定要完全抛弃底部导航。
  • 桌面体验优先

    • 如果 PC 端是主要使用场景,比如企业内部后台系统,可以考虑在 PC 上将底部导航替换为左侧垂直导航顶部标签栏
    • 此时需要在代码层面判断平台/尺寸,在不同端渲染不同导航组件,但业务路由层仍保持一致。

实际项目中常见的做法是:

  • 保持“模块划分”和“路由结构”在多端一致;
  • 仅改变如何呈现导航控件(底部栏 / 侧边栏 / TabBar)。

4. 与路由和返回栈的关系

底部导航不仅是一个 UI 组件,它还和路由、返回栈有紧密关系:

  • 用户在“首页 Tab”内部可能还会继续跳转到详情页;
  • 切到“消息 Tab”再返回时,期望看到的是上次停留的位置;
  • 再次点击已经选中的 Tab,有时设计为“回到该 Tab 的根页面”。

这些行为通常需要在路由层面做设计,例如:

  • 为每个 Tab 维护一个独立的 Navigator(嵌套导航栈);
  • 或在切换 Tab 时只记录状态,不销毁子树,从而保留滚动位置和内部路由。

本案例的实现是最简化版本:只展示了索引切换和页面内容替换的概念模型。在真实项目中,你可以在此基础上引入:

  • 嵌套路由(Nested Navigation);
  • 某种状态管理(如 Provider、Riverpod、Bloc 等)来保存各 Tab 的内部状态。

5. 设计与可用性的小细节

在实际设计底部导航时,还可以注意一些细节:

  • 图标与文案的清晰性:标签文案应简短但语义清晰,避免“更多”“功能”这类模糊词汇;
  • 选中态与未选中态的对比:选中项应在颜色、粗细或背景上明显区别,方便用户快速确认当前所在模块;
  • 避免频繁变动:一旦发布后,底部导航结构尽量不要频繁改动顺序或含义,否则会带来学习成本;
  • 支持无障碍:为导航项提供合适的语义标签(如 tooltip/辅助说明),便于读屏和键盘导航。

通过理解这些更深层次的设计原则,你可以在本案例的基础上,构建出既符合平台习惯、又易于维护和扩展的多端导航框架。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐