Does anyone have any recommendations for figuring out nested navigation in Flutter?
What I want is to keep a persistent BottomNavigationBar even when redirecting to new screens. Similar to YouTube, where the bottom bar is always there, even when you browse deeper into the menus.
I'm unable to figure it out from the docs.
The only tutorial I have been able to find so far that goes in-depth into exactly my requirement is https://medium.com/coding-with-flutter/flutter-case-study-multiple-navigators-with-bottomnavigationbar-90eb6caa6dbf (source code). However, It's super confusing.
Right now I'm using
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return Container()
However, its just pushing the new widget over the entire stack, covoring the BottomNavigationBar.
Any tips would be greatly appreciated!
Here is a simple example that even supports popping to the first screen with a tab bar.
import 'package:flutter/material.dart';
import '../library/screen.dart';
import '../playlists/screen.dart';
import '../search/screen.dart';
import '../settings/screen.dart';
class TabsScreen extends StatefulWidget {
@override
_TabsScreenState createState() => _TabsScreenState();
}
class _TabsScreenState extends State<TabsScreen> {
int _currentIndex = 0;
final _libraryScreen = GlobalKey<NavigatorState>();
final _playlistScreen = GlobalKey<NavigatorState>();
final _searchScreen = GlobalKey<NavigatorState>();
final _settingsScreen = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: <Widget>[
Navigator(
key: _libraryScreen,
onGenerateRoute: (route) => MaterialPageRoute(
settings: route,
builder: (context) => LibraryScreen(),
),
),
Navigator(
key: _playlistScreen,
onGenerateRoute: (route) => MaterialPageRoute(
settings: route,
builder: (context) => PlaylistsScreen(),
),
),
Navigator(
key: _searchScreen,
onGenerateRoute: (route) => MaterialPageRoute(
settings: route,
builder: (context) => SearchScreen(),
),
),
Navigator(
key: _settingsScreen,
onGenerateRoute: (route) => MaterialPageRoute(
settings: route,
builder: (context) => SettingsScreen(),
),
),
],
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
onTap: (val) => _onTap(val, context),
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.library_books),
title: Text('Library'),
),
BottomNavigationBarItem(
icon: Icon(Icons.list),
title: Text('Playlists'),
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text('Search'),
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
title: Text('Settings'),
),
],
),
);
}
void _onTap(int val, BuildContext context) {
if (_currentIndex == val) {
switch (val) {
case 0:
_libraryScreen.currentState.popUntil((route) => route.isFirst);
break;
case 1:
_playlistScreen.currentState.popUntil((route) => route.isFirst);
break;
case 2:
_searchScreen.currentState.popUntil((route) => route.isFirst);
break;
case 3:
_settingsScreen.currentState.popUntil((route) => route.isFirst);
break;
default:
}
} else {
if (mounted) {
setState(() {
_currentIndex = val;
});
}
}
}
}