Flutter:打开Drawer时隐藏BottomNavigationBar的实现疑问
解决方案
核心思路是监听首页Drawer的打开/关闭状态,动态控制底部导航栏的显示与隐藏,完全保留你现有多页面状态保存的结构,同时只在首页显示汉堡图标。
步骤1:修改父页面状态类,添加控制变量与全局Key
在承载底部导航栏的_HomePageState中,新增状态控制变量和Drawer全局Key:
bool _isBottomBarVisible = true; final GlobalKey<DrawerControllerState> _drawerKey = GlobalKey();
步骤2:监听Drawer状态变化
在initState中添加监听器,实时感知Drawer的开闭状态并更新底部导航栏显示状态:
@override void initState() { super.initState(); // 延迟执行确保Drawer已完成初始化 WidgetsBinding.instance.addPostFrameCallback((_) { _drawerKey.currentState?.addListener(() { setState(() { _isBottomBarVisible = !_drawerKey.currentState!.isOpen; }); }); }); }
步骤3:给首页Drawer绑定全局Key
修改Page组件的构造函数,新增drawerKey参数,用于给首页的Drawer绑定全局Key:
class Page extends StatelessWidget { const Page({ Key? key, required this.title, required this.drawer, this.drawerKey, // 新增参数 }) : super(key: key); final String title; final bool drawer; final GlobalKey<DrawerControllerState>? drawerKey; // 新增变量 @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), endDrawer: drawer ? Drawer(key: drawerKey) : null, // 绑定Key body: Center( child: Text( title, style: const TextStyle( fontSize: 45, fontWeight: FontWeight.w500, ), ), ), ); } }
步骤4:动态控制底部导航栏显示
用AnimatedOpacity+Visibility包裹底部导航栏,实现平滑的显示/隐藏动画:
bottomNavigationBar: AnimatedOpacity( opacity: _isBottomBarVisible ? 1.0 : 0.0, duration: const Duration(milliseconds: 200), child: Visibility( visible: _isBottomBarVisible, child: Container( color: Theme.of(context).primaryColor, height: 60, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ IconButton( onPressed: () { setState(() { pageIndex = 0; }); }, icon: const Icon(Icons.home_outlined), ), IconButton( onPressed: () { setState(() { pageIndex = 1; }); }, icon: const Icon(Icons.work_outline_outlined), ), IconButton( onPressed: () { setState(() { pageIndex = 2; }); }, icon: const Icon(Icons.widgets_outlined), ), ], ), ), ), ),
完整修改后的可复现代码
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const MaterialApp( home: HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int pageIndex = 0; bool _isBottomBarVisible = true; final GlobalKey<DrawerControllerState> _drawerKey = GlobalKey(); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { _drawerKey.currentState?.addListener(() { setState(() { _isBottomBarVisible = !_drawerKey.currentState!.isOpen; }); }); }); } @override Widget build(BuildContext context) { return Scaffold( // 用IndexedStack保存页面状态,和原逻辑一致 body: IndexedStack( index: pageIndex, children: [ Page( title: "page 1", drawer: true, drawerKey: _drawerKey, ), const Page(title: "page 2", drawer: false), const Page(title: "page 3", drawer: false), ], ), bottomNavigationBar: AnimatedOpacity( opacity: _isBottomBarVisible ? 1.0 : 0.0, duration: const Duration(milliseconds: 200), child: Visibility( visible: _isBottomBarVisible, child: Container( color: Theme.of(context).primaryColor, height: 60, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ IconButton( onPressed: () { setState(() { pageIndex = 0; }); }, icon: const Icon(Icons.home_outlined), ), IconButton( onPressed: () { setState(() { pageIndex = 1; }); }, icon: const Icon(Icons.work_outline_outlined), ), IconButton( onPressed: () { setState(() { pageIndex = 2; }); }, icon: const Icon(Icons.widgets_outlined), ), ], ), ), ), ), ); } } class Page extends StatelessWidget { const Page({ Key? key, required this.title, required this.drawer, this.drawerKey, }) : super(key: key); final String title; final bool drawer; final GlobalKey<DrawerControllerState>? drawerKey; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), endDrawer: drawer ? Drawer(key: drawerKey) : null, body: Center( child: Text( title, style: const TextStyle( fontSize: 45, fontWeight: FontWeight.w500, ), ), ), ); } }
额外说明
- 用
IndexedStack替代直接的pages[pageIndex],可以更好地保存每个页面的状态,和你原有的多导航器逻辑完全兼容。 - 动画效果用
AnimatedOpacity+Visibility组合,既保证隐藏时不占用布局空间,又有平滑的过渡动画,实现成本低且效果自然。 - 仅首页绑定了Drawer的全局Key,其他页面不受影响,完全符合你“只在首页显示汉堡图标”的需求。
内容的提问来源于stack exchange,提问作者Davinci Cake
相关产品推荐
相关产品推荐

