Flutter跨平台生活助手App开发实战:实现凸起式底部导航栏
本文介绍了使用Flutter的convex_bottom_bar库实现应用底部导航栏的过程。主要内容包括: 选择convex_bottom_bar的原因:相比原生组件提供更多样式选择,特别是中间凸起的圆形按钮效果 主页面实现:通过_currentIndex状态管理四个Tab页切换,使用ConvexAppBar配置导航栏样式 性能优化建议:介绍了IndexedStack和AutomaticKeepA

上一篇文章我们搭建好了项目的基础架构,今天来实现应用的底部导航栏。这个导航栏是整个应用的骨架,用户通过它在不同功能模块之间切换。我选择了convex_bottom_bar这个库,它能做出中间凸起的效果,视觉上比较有特色。
为什么选择convex_bottom_bar
Flutter自带的BottomNavigationBar虽然也能用,但样式比较普通。convex_bottom_bar提供了多种样式,特别是那个中间凸起的圆形按钮,看起来更有设计感。而且这个库在鸿蒙系统上也能正常工作,不用担心兼容性问题。
先在pubspec.yaml里添加依赖:
dependencies:
convex_bottom_bar: ^3.0.0
主页面的实现
主页面MainPage是整个应用的容器,它管理着四个Tab页面的切换。来看看具体代码:
import 'package:flutter/material.dart';
import 'package:convex_bottom_bar/convex_bottom_bar.dart';
import 'home/home_page.dart';
import 'finance/finance_page.dart';
import 'life/life_page.dart';
import 'profile/profile_page.dart';
class MainPage extends StatefulWidget {
const MainPage({super.key});
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int _currentIndex = 0;
final List<Widget> _pages = [
const HomePage(),
const FinancePage(),
const LifePage(),
const ProfilePage(),
];
void initState() {
super.initState();
debugPrint('📄 MainPage initialized');
}
Widget build(BuildContext context) {
debugPrint('🎨 MainPage building with index: $_currentIndex');
return Scaffold(
body: _pages[_currentIndex],
bottomNavigationBar: ConvexAppBar(
style: TabStyle.reactCircle,
backgroundColor: Colors.blue,
items: const [
TabItem(icon: Icons.home, title: '首页'),
TabItem(icon: Icons.account_balance_wallet, title: '记账'),
TabItem(icon: Icons.calendar_today, title: '生活'),
TabItem(icon: Icons.person, title: '我的'),
],
initialActiveIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
);
}
}
这段代码的核心逻辑很简单:
状态管理:用_currentIndex记录当前选中的Tab索引,初始值是0,也就是首页。
页面列表:_pages数组存放四个页面的实例,通过索引来显示对应的页面。
导航栏配置:ConvexAppBar的style设置为TabStyle.reactCircle,这样点击时会有圆形的反应效果。backgroundColor设置成蓝色,和应用的主题色保持一致。
点击事件:onTap回调里调用setState更新索引,触发页面重建,显示新的页面。
关于页面切换的性能优化
你可能注意到,每次切换Tab都会重建页面。如果页面比较复杂,这样会有性能问题。有个简单的优化方法,就是用IndexedStack替代直接显示页面:
body: IndexedStack(
index: _currentIndex,
children: _pages,
)
IndexedStack会把所有页面都保持在内存里,只是显示当前索引对应的那个。这样切换时不需要重建页面,滚动位置、输入内容这些状态都能保留。
不过这样做也有代价,就是内存占用会增加。如果页面不是特别复杂,用原来的方式就够了。我在实际使用中发现,对于这个应用来说,直接切换页面的性能已经很流畅了。
导航栏的样式定制
convex_bottom_bar提供了好几种样式,我试过几个:
TabStyle.reactCircle:点击时有圆形反应效果,这是我最终选择的样式。
TabStyle.fixedCircle:中间按钮固定凸起,不会跟随点击移动。
TabStyle.textIn:文字显示在图标内部。
TabStyle.titled:文字显示在图标下方,比较传统的样式。
如果你想自定义颜色,可以这样配置:
ConvexAppBar(
backgroundColor: Colors.blue, // 背景色
activeColor: Colors.white, // 选中时的颜色
color: Colors.white70, // 未选中时的颜色
height: 50, // 导航栏高度
// ...
)
四个Tab页面的基础框架
现在四个页面还只是占位符,先创建最基本的结构。以首页为例:
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
const HomePage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('生活助手'),
),
body: const Center(
child: Text('首页 - 健康管理'),
),
);
}
}
其他三个页面也是类似的结构,只是标题和内容不同。这样先把框架搭起来,后面再逐个实现具体功能。
调试技巧
开发过程中,我在initState和build方法里加了一些调试日志:
void initState() {
super.initState();
debugPrint('📄 MainPage initialized');
}
Widget build(BuildContext context) {
debugPrint('🎨 MainPage building with index: $_currentIndex');
// ...
}
这些日志能帮我了解页面的生命周期,比如什么时候初始化,什么时候重建。用emoji做标记,在一堆日志里很容易找到自己关心的信息。
遇到的一个小问题
一开始我发现切换Tab时,键盘如果是打开状态,会把导航栏顶上去。解决方法是在Scaffold里加一行配置:
Scaffold(
resizeToAvoidBottomInset: false, // 不调整大小
// ...
)
这样键盘弹出时,导航栏的位置就不会变了。
关于页面状态保持
如果你希望切换Tab后,页面的状态能保持住(比如滚动位置、输入的内容),可以让页面继承AutomaticKeepAliveClientMixin:
class HomePage extends StatefulWidget {
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with AutomaticKeepAliveClientMixin {
bool get wantKeepAlive => true;
Widget build(BuildContext context) {
super.build(context); // 这行很重要,不能忘
return Scaffold(/* ... */);
}
}
wantKeepAlive返回true表示要保持状态,build方法里必须调用super.build(context),这是mixin的要求。
实际使用体验
导航栏实现后,我在真机上测试了一下,切换很流畅,没有卡顿。中间凸起的按钮点击起来手感也不错,视觉上比平铺的导航栏更有层次感。
唯一需要注意的是,convex_bottom_bar的高度是固定的,如果你的设计稿要求特定高度,可能需要调整一下。我用的是默认高度,在不同屏幕上看起来都还可以。
下一步计划
底部导航栏搭好了,接下来要实现首页的健康仪表盘功能。那里会用到图表展示,涉及到fl_chart库的使用,还有一些数据可视化的技巧,我会在下一篇详细介绍。
小结
今天实现了应用的底部导航栏,用convex_bottom_bar做出了凸起式的效果。核心是通过_currentIndex状态来控制页面切换,配合setState触发UI更新。还分享了一些性能优化和状态保持的技巧。
这个导航栏是整个应用的基础框架,后面所有功能都会在这四个Tab里展开。有了这个框架,开发起来就有条理多了。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)