Flutter开发:如何让Drawer显示在BottomNavigationBar下方?
问题描述
我希望在Flutter应用中同时使用BottomNavigationBar与Drawer组件。当前打开Drawer时,BottomNavigationBar处于Drawer下方(被Drawer覆盖),我想要实现Drawer显示在BottomNavigationBar下方的效果,请问该需求是否可行?
用户原实现代码:
Scaffold( key: _scaffoldKey, appBar: PreferredSize( preferredSize: Size(0.0, 0.0), child: Container(), ), drawer: DrawerWidget(Theme.of(context).brightness, _selectedDrawerIndex, onSelectItem, widget._operator.plannerEnabled, widget._operatorRepository), body: _getDrawerItemWidget(_selectedDrawerIndex), floatingActionButton: !_showBottoNav() && plannerEnabled ? FloatingActionButton( elevation: 0.0, backgroundColor: Theme.of(context).primaryColor, child: Icon( Icons.arrow_forward, color: Colors.white, ), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ChangeNotifierProvider( create: (context) => PlannerHomeViewModel(context, widget._operator, null, null, null), child: PlannerHomeScreen(), ), ), ); }, ) : null, floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, bottomNavigationBar: !_showBottoNav() ? BottomNav( onTap: changeSelectedIndex, openMenu: manageDrawer, showPlanner: plannerEnabled, currentIndex: _selectedDrawerIndex ?? 1, ) : null, ),
实现方案
这个需求完全可行,默认Scaffold的drawer参数会把Drawer渲染在所有内容之上,要让Drawer显示在BottomNavigationBar下方,需要调整组件层级,具体步骤如下:
- 移除Scaffold自带的
drawer参数,把Drawer作为独立组件放到Scaffold的body层级中 - 用
Stack管理body内的元素,将Drawer放在Stack的底层,页面内容放在上层,这样Drawer会被页面内容覆盖,而BottomNavigationBar因为是Scaffold的bottomNavigationBar参数,层级高于body,自然会显示在Drawer上方 - 手动维护Drawer的显示/隐藏状态,通过布尔值控制,并添加手势实现点击空白关闭Drawer的效果
修改后的完整代码示例:
bool _isDrawerOpen = false; @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, appBar: PreferredSize( preferredSize: Size(0.0, 0.0), child: Container(), ), body: Stack( children: [ // Drawer 置于最底层 if (_isDrawerOpen) GestureDetector( // 点击遮罩关闭Drawer onTap: () => setState(() => _isDrawerOpen = false), child: Container( color: Colors.black54, child: DrawerWidget( Theme.of(context).brightness, _selectedDrawerIndex, (index) { setState(() { _selectedDrawerIndex = index; _isDrawerOpen = false; }); onSelectItem(index); }, widget._operator.plannerEnabled, widget._operatorRepository, ), ), ), // 页面内容置于Drawer上层 GestureDetector( onTap: () { if (_isDrawerOpen) setState(() => _isDrawerOpen = false); }, child: _getDrawerItemWidget(_selectedDrawerIndex), ), ], ), floatingActionButton: !_showBottoNav() && plannerEnabled ? FloatingActionButton( elevation: 0.0, backgroundColor: Theme.of(context).primaryColor, child: Icon( Icons.arrow_forward, color: Colors.white, ), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ChangeNotifierProvider( create: (context) => PlannerHomeViewModel(context, widget._operator, null, null, null), child: PlannerHomeScreen(), ), ), ); }, ) : null, floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, bottomNavigationBar: !_showBottoNav() ? BottomNav( onTap: changeSelectedIndex, // 修改openMenu方法,切换Drawer显示状态 openMenu: () => setState(() => _isDrawerOpen = true), showPlanner: plannerEnabled, currentIndex: _selectedDrawerIndex ?? 1, ) : null, ); }
关键说明
- 移除了Scaffold原生的
drawer,避免其默认的层级覆盖逻辑 - 通过
Stack的子组件顺序控制层级,Drawer在最下层,页面内容在中间层,BottomNavigationBar在最上层 - 添加了遮罩层和点击关闭手势,模拟原生Drawer的交互体验
- 手动控制
_isDrawerOpen状态来管理Drawer的显示与隐藏
内容的提问来源于stack exchange,提问作者Dawid Długosz
相关产品推荐
相关产品推荐

