Flutter中Drawer切换页面时BottomNavigationBar消失问题求助
我希望在所有页面复用NavigationBar组件,BottomNavigationBar在主页面运行正常,但通过Drawer切换页面时该组件会消失。已参考相关教程,但仅主页面显示该组件。我尝试过将NavBar封装为独立StatefulWidget,并复制到需要显示该栏的页面的bottomNavigationBar中,但问题仍未解决。以下是我的主页代码:
import 'package:flutter/material.dart'; import 'package:kikapp/create.dart'; import 'package:kikapp/home.dart'; import 'package:kikapp/zero.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'KikApp', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.grey), useMaterial3: true, ), debugShowCheckedModeBanner: false, initialRoute: 'home', routes: { 'home': (context) => const Main(), 'profile': (context) => const Create(), 'zero': (context) => const Zero(), } ); } } //Drawer class MyDrawer extends StatelessWidget { const MyDrawer({super.key}); @override Widget build(BuildContext context) { return Drawer( child: ListView( padding: EdgeInsets.zero, children: [ const DrawerHeader( decoration: BoxDecoration( color: Colors.black12, ), child: Text( 'Anarkika', style: TextStyle( color: Colors.white, fontSize: 24, ), ), ), ListTile( leading: const Icon(Icons.home), title: const Text('Home'), onTap: () { Navigator.pop(context); Navigator.of(context).push( MaterialPageRoute(builder: (context) => const Home())); }, ), ListTile( leading: const Icon(Icons.book), title: const Text('Zero'), onTap: () { Navigator.pop(context); Navigator.of(context).push( MaterialPageRoute(builder: (context) => const Zero())); }, ), ListTile( leading: const Icon(Icons.add), title: const Text('Create'), onTap: () { Navigator.pop(context); Navigator.of(context).push( MaterialPageRoute(builder: (context) => const Create())); }, ), ], ), ); } } //Body class Main extends StatefulWidget { const Main({super.key}); @override State<Main> createState() => _MainState(); } class _MainState extends State<Main> { int index = 0; final pages = [ const Home(), const Zero(), const Create(), ]; @override Widget build(BuildContext context) { return Scaffold( body: pages[index], bottomNavigationBar: NavigationBar( height: 70, animationDuration: const Duration(milliseconds: 1000), labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected, backgroundColor: Colors.grey, indicatorColor: Colors.white, selectedIndex: index, onDestinationSelected: (index) => setState(() => this.index = index), destinations: const [ NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: 'Home',), NavigationDestination(icon: Icon(Icons.book_outlined), selectedIcon: Icon(Icons.book), label: 'Zero',), NavigationDestination(icon: Icon(Icons.add_outlined), selectedIcon: Icon(Icons.add), label: 'Create',), ], ), ); } } class Nav extends StatefulWidget { const Nav({ Key? key }) : super(key: key); @override State<Nav> createState() => _NavState(); } class _NavState extends State<Nav> { int index = 0; final pages = [ const Home(), const Zero(), const Create(), ]; @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: NavigationBar( animationDuration: const Duration(milliseconds: 1500), labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected, backgroundColor: Colors.grey, indicatorColor: Colors.white, selectedIndex: index, onDestinationSelected: (index) => setState(() => this.index = index), destinations: const [ NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: 'Home',), NavigationDestination(icon: Icon(Icons.book_outlined), selectedIcon: Icon(Icons.book), label: 'Zero',), NavigationDestination(icon: Icon(Icons.add_outlined), selectedIcon: Icon(Icons.add), label: 'Create',), ], ), ); } }
核心问题是Drawer切换页面时,你直接push了独立的页面组件(如Home、Zero、Create),这些组件本身没有包裹在带有BottomNavigationBar的Scaffold中。而主页面Main是通过切换body内容来展示不同页面,BottomNavigationBar属于Main的Scaffold,所以主页正常;但Drawer跳转时绕过了Main的结构,直接打开了无底部导航的页面。
1. 统一页面容器,所有页面都在Main的body中切换
修改Drawer的跳转逻辑,不要直接push新页面,而是通知Main页面切换当前展示的index,始终保持Main的Scaffold作为容器:
修改MyDrawer组件,添加页面切换回调
class MyDrawer extends StatelessWidget { final Function(int) onPageSelected; const MyDrawer({super.key, required this.onPageSelected}); @override Widget build(BuildContext context) { return Drawer( child: ListView( padding: EdgeInsets.zero, children: [ const DrawerHeader( decoration: BoxDecoration( color: Colors.black12, ), child: Text( 'Anarkika', style: TextStyle( color: Colors.white, fontSize: 24, ), ), ), ListTile( leading: const Icon(Icons.home), title: const Text('Home'), onTap: () { Navigator.pop(context); onPageSelected(0); }, ), ListTile( leading: const Icon(Icons.book), title: const Text('Zero'), onTap: () { Navigator.pop(context); onPageSelected(1); }, ), ListTile( leading: const Icon(Icons.add), title: const Text('Create'), onTap: () { Navigator.pop(context); onPageSelected(2); }, ), ], ), ); } }
修改Main页面,添加Drawer并处理切换回调
class _MainState extends State<Main> { int index = 0; final pages = [ const Home(), const Zero(), const Create(), ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: Builder( builder: (context) => IconButton( icon: const Icon(Icons.menu), onPressed: () => Scaffold.of(context).openDrawer(), ), ), ), drawer: MyDrawer(onPageSelected: (selectedIndex) { setState(() { index = selectedIndex; }); }), body: pages[index], bottomNavigationBar: NavigationBar( height: 70, animationDuration: const Duration(milliseconds: 1000), labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected, backgroundColor: Colors.grey, indicatorColor: Colors.white, selectedIndex: index, onDestinationSelected: (index) => setState(() => this.index = index), destinations: const [ NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: 'Home',), NavigationDestination(icon: Icon(Icons.book_outlined), selectedIcon: Icon(Icons.book), label: 'Zero',), NavigationDestination(icon: Icon(Icons.add_outlined), selectedIcon: Icon(Icons.add), label: 'Create',), ], ), ); } }
2. 简化路由配置
移除routes中指向单独页面的配置,统一指向Main即可:
routes: { '/': (context) => const Main(), }, initialRoute: '/',
3. 删除多余的Nav组件
Nav组件无需单独封装,Main已经承担了容器和底部导航的管理角色,所有页面切换都在Main内部完成,BottomNavigationBar只需要维护一份。
这样修改后,无论是通过BottomNavigationBar还是Drawer切换页面,都会在Main的Scaffold中切换body内容,BottomNavigationBar会始终显示在页面底部。
内容的提问来源于stack exchange,提问作者Dudu Sandoval Gamarra

