If this is what you want to achieve, then this post is for you.
Normally, for the mobile app, using the BottomNavigationBar would be fine. However, BottomNavigationBar for a desktop website? No one do that!
So here is the alternative.
Introducing NavigationRail, this is an ideal widget for implementing sidebar on the web/desktop application.
1. Where to Put?
Well, since it's a sidebar, therefore this widget will be insert in the either left or right side of your page, and in order to do that, we will use Row widget.
class PageWithSideBar extends StatefulWidget {
const PageWithSideBar({Key? key}) : super(key: key);
@override
State<PageWithSideBar> createState() => _PageWithSideBarState();
}
class _PageWithSideBarState extends State<PageWithSideBar> {
int _selectedIndex = 0;
final List<String> _destinations = ['Home', 'Calendar', 'Email'];
Widget _buildNavigationRail() {
return Container() //TODO: We are going to implement here
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
_buildNavigationRail(), // HERE: This is our SideBar
Expanded(
child: Center(
child: Text('This is ${_destinations[_selectedIndex]} Page'),
),
)
],
),
);
}
}
Notice that we use Expanded widget in our main content so it will take all the space as much as possible.
2. Now let's implement NavigationRail.
Widget _buildNavigationRail() {
return NavigationRail(
labelType: NavigationRailLabelType.selected,
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.home_outlined),
selectedIcon: Icon(Icons.home),
label: Text('Home'),
),
NavigationRailDestination(
icon: Icon(Icons.calendar_month_outlined),
selectedIcon: Icon(Icons.calendar_month),
label: Text('Calendar'),
),
NavigationRailDestination(
icon: Icon(Icons.email_outlined),
selectedIcon: Icon(Icons.email),
label: Text('Email'),
),
],
);
}
Let's see how it turned out
In my opinion, this sidebar still look like an mobile one, so what about make it feel more like a website's sidebar?
We are going to do that by make it become Expandable side bar. Good news is that the Flutter Dev know exactly what we want, as there is an property call extended, so why don't we set its value to "true"?
dart
NavigationRail(
extended: true,
labelType: NavigationRailLabelType.selected, ...)
Whoa, There is error here. It's mention that if we set the "extended" to true, then we have to set the labelType to "none"
Okay understandable, since having both label at the bottom of the icon and next to the icon would be really weird.
dart
NavigationRail(
extended: true,
labelType: NavigationRailLabelType.none, ...)
Now the error is gone
But hey, seems like something is missing here... It should be togglable, so we should have something like menu icon.
Okay, here is my solution,
- Declare new boolean variable call _isExtended as a property of NavigationRail
- Add AppBar with the IconButton to toggle the state of _isExtended
Here is the code
dart
class PageWithSideBar extends StatefulWidget {
const PageWithSideBar({Key? key}) : super(key: key);
@override
State<PageWithSideBar> createState() => _PageWithSideBarState();
}
class _PageWithSideBarState extends State<PageWithSideBar> {
int _selectedIndex = 0;
final List<String> _destinations = ['Home', 'Calendar', 'Email'];
bool _isExpanded = false; //NEW VARIABLE
Widget _buildNavigationRail() {
return NavigationRail(
extended: _isExpanded, //NEW VARIABLE
labelType: NavigationRailLabelType.none,
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.home_outlined),
selectedIcon: Icon(Icons.home),
label: Text('Home'),
),
NavigationRailDestination(
icon: Icon(Icons.calendar_month_outlined),
selectedIcon: Icon(Icons.calendar_month),
label: Text('Calendar'),
),
NavigationRailDestination(
icon: Icon(Icons.email_outlined),
selectedIcon: Icon(Icons.email),
label: Text('Email'),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar( //ADDED APP BAR
title: const Text('Navigation Rails Example'),
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
),
),
body: Row(
children: <Widget>[
_buildNavigationRail(),
Expanded(
child: Center(
child: Text('This is ${_destinations[_selectedIndex]} Page'),
),
)
],
),
);
}
}
Here is the full code
dart
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Navigation Rails Example';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: PageWithSideBar(),
);
}
}
class PageWithSideBar extends StatefulWidget {
const PageWithSideBar({Key? key}) : super(key: key);
@override
State<PageWithSideBar> createState() => _PageWithSideBarState();
}
class _PageWithSideBarState extends State<PageWithSideBar> {
int _selectedIndex = 0;
final List<String> _destinations = ['Home', 'Calendar', 'Email'];
bool _isExpanded = false;
Widget _buildNavigationRail() {
return NavigationRail(
extended: _isExpanded,
labelType: NavigationRailLabelType.none,
selectedIndex: _selectedIndex,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.home_outlined),
selectedIcon: Icon(Icons.home),
label: Text('Home'),
),
NavigationRailDestination(
icon: Icon(Icons.calendar_month_outlined),
selectedIcon: Icon(Icons.calendar_month),
label: Text('Calendar'),
),
NavigationRailDestination(
icon: Icon(Icons.email_outlined),
selectedIcon: Icon(Icons.email),
label: Text('Email'),
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar( //ADDED APP BAR
title: const Text('Navigation Rails Example'),
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
),
),
body: Row(
children: <Widget>[
_buildNavigationRail(),
Expanded(
child: Center(
child: Text('This is ${_destinations[_selectedIndex]} Page'),
),
)
],
),
);
}
}
Ok we are good to go now.
Thank you for reading.
Top comments (0)