I have a simple app, with 3 bottom nav items.
However, when I click on one of the bottom nav items bellow, the entire page is moving, from right to left with iOS, from bottom with android.
I want my bottom navigation app to stay at the same place, as traditionnal Bottom Nav Bar
I know I can find working implementations of bottom navigation bar using a StatefulWidget
, a int _selectedIndex = 0;
and a static const List<Widget> _widgetOptions
,
but my app is already big and using a different mecanism in 3 steps defines below : (that you find on my github repo) :
1. MaterialApp defines _onGenerateRoute :
main.dart
MaterialApp(
title: 'Keep bottom navigation',
themeMode: ThemeMode.dark,
onGenerateRoute: _generateRoute,
);
main.dart
Route<dynamic> _generateRoute(RouteSettings settings) {
switch (settings.name) {
case AppRoutes.computer:
return MaterialPageRoute(builder: (context) => ComputerScreen());
case AppRoutes.phone:
return MaterialPageRoute(builder: (context) => PhoneScreen());
case AppRoutes.person:
default:
return MaterialPageRoute(builder: (context) => PersonScreen());
}
}
route_config.dart
class AppRoutes {
static const String computer = '/computer';
static const String phone = '/phone';
static const String person = '/person';
}
2. Every screens extends BaseScreen as a State :
screens/computer_screen.dart
class ComputerScreen extends StatefulWidget {
@override
_ComputerScreenState createState() => _ComputerScreenState();
}
class _ComputerScreenState extends BaseScreenState<ComputerScreen> {
@override
String get currentRoute => AppRoutes.computer;
@override
Widget buildScreen(BuildContext context) {
return Center(
child:
Text("Computer screen", style: Theme.of(context).textTheme.headline3),
);
}
}
3. Base Sceen defines the basics of a screen :
base_screen.dart
import 'package:flutter/material.dart';
import 'package:keep_bottomnav/bottom_nav_bar.dart';
abstract class BaseScreenState<T extends StatefulWidget> extends State<T> {
String get currentRoute;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: this.buildAppBar(context),
body: this.buildScreen(context),
bottomNavigationBar: this.buildBottomNavigationBar(context),
floatingActionButton: this.buildFloatingActionButton(context),
);
}
Widget buildScreen(BuildContext context);
PreferredSizeWidget buildAppBar(BuildContext context) {
return null;
}
Widget buildBottomNavigationBar(BuildContext context) {
return BottomNavBar(
selectedRoute: currentRoute,
onSelectRoute: _onItemTapped,
);
}
Widget buildFloatingActionButton(BuildContext context) {
return null;
}
bool get centerFloatingActionButton => false;
void _onItemTapped(String route) {
Navigator.pushNamedAndRemoveUntil(context, route, (route) => false);
}
}
4. UI of BottomNavBar
import 'package:flutter/material.dart';
import 'package:keep_bottomnav/bottom_nav_bar_item.dart';
import 'package:keep_bottomnav/route_config.dart';
class BottomNavBar extends StatelessWidget {
final String selectedRoute;
final ValueChanged<String> onSelectRoute;
BottomNavBar({this.selectedRoute, this.onSelectRoute});
@override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
double itemWidth = (screenWidth / 3);
return Material(
color: Colors.white,
child: SafeArea(
child: Container(
padding: const EdgeInsets.only(bottom: 10),
color: Colors.white,
height: 65,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
_buildNavigationItem(
AppRoutes.computer,
icon: Icon(Icons.computer),
title: "Computer 1",
itemWidth: itemWidth,
),
_buildNavigationItem(
AppRoutes.phone,
icon: Icon(Icons.phone),
title: "Phone 2",
itemWidth: itemWidth,
),
_buildNavigationItem(
AppRoutes.person,
icon: Icon(Icons.person),
title: "Person 3",
itemWidth: itemWidth,
),
],
),
),
),
);
}
Widget _buildNavigationItem(String route,
{Widget icon, String title, itemWidth}) {
return BottomNavBarItem(
isSelected: selectedRoute == route,
icon: icon,
title: title,
minWidth: itemWidth,
onTap: () {
if (onSelectRoute != null) {
onSelectRoute(route);
}
},
);
}
}
import 'package:flutter/material.dart';
class BottomNavBarItem extends StatelessWidget {
final bool isSelected;
final VoidCallback onTap;
final Widget icon;
final String title;
final double minWidth;
BottomNavBarItem(
{Key key,
@required this.icon,
@required this.title,
this.isSelected = false,
this.onTap,
this.minWidth = 50})
: super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
onTap: this.onTap,
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: 0),
child: Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: isSelected ? Colors.yellow : Colors.transparent,
width: 3.0))),
padding: const EdgeInsets.only(top: 10, left: 10, right: 10),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
icon,
Text(
title.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 9.0),
)
],
),
),
),
);
}
}
Thank you very much for your help
Using Hero on BottomNavItems was buggy