Flutter — Simple Bottom Navigation Tutorial

Zeba Rahman
fabcoding
Published in
2 min readMay 29, 2020

Bottom navigation is a common design pattern for placing top-level and frequently-used actions. Let us implement it using Flutter.

The child screens

We will need three screen-widgets for showing different screens for each tab. Create simple stateful widgets in three files, as below for Home, Search and Profile screens.

home_screen.dart

class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Container();
}
}

search_screen.dart

class SearchScreen extends StatefulWidget {
@override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
@override
Widget build(BuildContext context) {
return Container();
}
}

profile_screen.dart

class ProfileScreen extends StatefulWidget {
@override
_ProfileScreenState createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
@override
Widget build(BuildContext context) {
return Container();
}
}

The parent screen

Now let us create a stateful widget for the main screen that will hold the tabbar and allow switching between tabs, and display the selected screen.

tabbar_screen.dart

class TabBarScreen extends StatefulWidget {
@override
_TabBarScreenState createState() => _TabBarScreenState();
}
class _TabBarScreenState extends State<TabBarScreen> {

@override

Widget build(BuildContext context) {

return Container();
}
}

Declare a variable to store the list of our child screens in a list, and another to hold the current active screen index.

List<Widget> pageList = List<Widget>();
int _currentIndex = 0;

Initialise the state by adding the screens to the list.

@override
void initState() {
pageList.add(HomeScreen());
pageList.add(SearchScreen());
pageList.add(ProfileScreen());
super.initState();
}

Finally, we modify the build method to return an indexed stack, with bottom navigation bar and a view that shows the currently selected screen.

We are using an IndexedStack so that the state is preserved, that is, the screens are not recreated each time it is changed. Alternatively, this can also be achieved by using a PageView along with AutomaticKeepAliveClientMixin.

@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: pageList,
),
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text(
'HOME',
),
),
BottomNavigationBarItem(
icon: new Icon(Icons.search),
title: new Text(
'SEARCH',
),
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: Text(
'PROFILE',
)
),
],
),
);
}

Implement the method that we called above, for onTap event of BottomNavigationBar

void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}

Run the app, now you can see a screen with three tabs on the bottom, and the view is loaded according to the selected tab.

Originally published at Fabcoding.

--

--