I want to close my Drawer
widget every time the user presses a button in the Bottom Navigation Bar
, but can't quite figure this thing out. The way my setup of the BNB is set now is that the current state of all screen is remembered through out the app (using an IndexedStack
), but I want to close the Drawer if it is opened in any of the screens before the BNB button press. Each of my screens have their own Drawers and AppBars, so I can't make one Drawer inside the BNB (or I can and I can dynamically change them with a switch case when a specific Screen is clicked on BUT then the Drawer will cover the Bottom Navigation Bar etc.), but I want to make it work like this for now. So here is the code with some comments inside to explain things:
Bottom Navigation Bar:
class BottomNavBar extends StatefulWidget {
static const String id = 'bottom_navbar_screen';
@override
_BottomNavBarState createState() => _BottomNavBarState();
}
class _BottomNavBarState extends State<BottomNavBar> {
int _selectedIndex = 0;
/// list of screen that will render inside the BNB
List<Navigation> _items = [
Navigation(
widget: Screen1(), navigationKey: GlobalKey<NavigatorState>()),
Navigation(
widget: Screen2(), navigationKey: GlobalKey<NavigatorState>()),
Navigation(
widget: Screen3(), navigationKey: GlobalKey<NavigatorState>()),
Navigation(
widget: Screen4(), navigationKey: GlobalKey<NavigatorState>()),
];
/// function that renders components based on selected one in the BNB
void _onItemTapped(int index) {
if (index == _selectedIndex) {
_items[index]
.navigationKey
.currentState
.popUntil((route) => route.isFirst);
} else {
setState(() {
_selectedIndex = index;
});
}
/// when the index is selected, on the button press do some actions
switch (_selectedIndex) {
case 0:
// Do some actions
break;
case 1:
// Do some actions
break;
case 2:
// Do some actions
break;
case 3:
// Do some actions
break;
}
}
/// navigation Tab widget for a list of all the screens and puts them in a Indexed Stack
Widget _navigationTab(
{GlobalKey<NavigatorState> navigationKey, Widget widget}) {
return Navigator(
key: navigationKey,
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(builder: (context) => widget);
},
);
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
final isFirstRouteInCurrentTab =
!await _items[_selectedIndex].navigationKey.currentState.maybePop();
if (isFirstRouteInCurrentTab) {
if (_selectedIndex != 0) {
_onItemTapped(1);
return false;
}
}
/// let system handle back button if we're on the first route
return isFirstRouteInCurrentTab;
},
child: Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: _items
.map((e) => _navigationTab(
navigationKey: e.navigationKey, widget: e.widget))
.toList(),
),
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
label: 'Screen 1,
),
BottomNavigationBarItem(
label: 'Screen 2,
),
BottomNavigationBarItem(
label: 'Screen 3,
),
BottomNavigationBarItem(
label: 'Screen 4,
),
],
currentIndex: _selectedIndex,
showUnselectedLabels: true,
onTap: _onItemTapped,
),
),
);
}
}
Let's say all 4 screens are the same and they have their own AppBar and Drawer:
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
drawer: Drawer(), // so this is what I want to close on BNB button press in each of the 4 screens
appBar: AppBar( // each screen has its own app bar
title: Text('Screens 1-4'),
),
body: Text('Body of Screens 1-4'),
);
}
So because each of the screens have their own AppBars and Drawers, the Drawer doesn't render over the Bottom Navigation Bar, so my BNB buttons can be clicked. If I put one Drawer for all Screens inside the BNB, then you can't click the BNB unless you close the Drawer first, which is not something I'm looking for right now.
So, my final question is, how do I close each of the Screens Drawers (if they are previously opened that is) when you press the BottomnavigationBar? (i.e. I am on Screen 1, I open the Drawer, then I press on Screen 2 in the BNB and I want to pop()
/close the Drawer in Screen 1 before I navigate to Screen 2.)
Thanks in advance for your help!