Flutter中如何在BottomNavigationBar同一图标下跳转页面
问题
已实现带有3个图标的BottomNavigationBar,每个图标对应一个页面。但希望从第一个图标对应的页面(索引0)跳转到其他页面时,保持该图标的选中状态,且BottomNavigationBar不消失。目前使用Navigator.push跳转时,底部导航栏会消失,因为打开了全新页面。
解决方案
核心思路是让每个Tab页面拥有独立的导航栈,这样Tab内部的页面跳转不会影响外层的BottomNavigationBar。具体实现方式是给每个Tab对应的页面嵌套Navigator组件,而非直接使用全局Navigator。
修改步骤
- 为每个Tab分配独立的
GlobalKey<NavigatorState>,用于管理Tab内的导航状态 - 使用
Stack + Offstage组合控制Tab页面的显示/隐藏,保留未选中Tab的状态 - 让每个Tab页面在自身的Navigator栈内完成跳转
完整代码示例
修改后的MainPage代码
class MainPage extends StatefulWidget { const MainPage({Key? key}) : super(key: key); @override _MainPageState createState() => _MainPageState(); } class _MainPageState extends State<MainPage> { int currentIndex = 0; // 为每个Tab维护独立的Navigator状态Key final List<GlobalKey<NavigatorState>> _navigatorKeys = [ GlobalKey<NavigatorState>(), GlobalKey<NavigatorState>(), GlobalKey<NavigatorState>(), ]; @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: BottomNavigationBar( backgroundColor: const Color(0xfffbfbfb), currentIndex: currentIndex, selectedItemColor: const Color(0xff5bc0de), unselectedItemColor: Colors.black, type: BottomNavigationBarType.shifting, onTap: (index) { // 点击当前选中Tab时,返回该Tab的根页面 if (index == currentIndex) { _navigatorKeys[index].currentState?.popUntil((route) => route.isFirst); } else { setState(() { currentIndex = index; }); } }, items: const [ BottomNavigationBarItem( icon: Image.asset("assets/home.png"), label: "Home", ), BottomNavigationBarItem( icon: Image.asset("assets/meeting.png"), label: "Schedule", ), BottomNavigationBarItem( icon: Image.asset("assets/notification.png"), label: "Alert", ), ], ), body: Stack( children: List.generate(3, (index) { return Offstage( offstage: currentIndex != index, child: Navigator( key: _navigatorKeys[index], onGenerateRoute: (settings) { return MaterialPageRoute( builder: (context) { // 根据索引返回对应Tab的初始页面 switch (index) { case 0: return const Home(); case 1: return const Home(); // 替换为你的Schedule页面 case 2: return const Home(); // 替换为你的Alert页面 default: return const Home(); } }, ); }, ), ); }), ), ); } }
修改后的Home页面代码
class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); @override _HomeState createState() => _HomeState(); } class _HomeState extends State<Home> { @override Widget build(BuildContext context) { return Scaffold( body: Container( width: 800, height: 800, color: Colors.blue, child: Center( child: InkWell( onTap: () { // 在当前Tab的Navigator栈内跳转,不影响外层导航栏 Navigator.push( context, MaterialPageRoute(builder: (context) => const Second()), ); }, child: const Text("helllo"), ), ), ), ); } } // 示例跳转目标页面 class Second extends StatelessWidget { const Second({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Second Page")), body: const Center(child: Text("This is Second Page")), ); } }
原理说明
- 独立Navigator栈:每个Tab的页面跳转都在自身Navigator中完成,外层Scaffold的BottomNavigationBar始终保持可见
- GlobalKey控制:通过GlobalKey可以精准控制每个Tab内的导航状态,比如点击当前Tab时返回根页面
- Stack + Offstage:未选中的Tab会被隐藏但保留状态,切换Tab时不会重新初始化页面,提升体验
内容的提问来源于stack exchange,提问作者Ahmed Elsayed
相关产品推荐
相关产品推荐

