Flutter: selected Icon on BottomNavigationBar doesn't change when tap - flutter

I work on flutter and I make an app with 5 tabs, using a BottomNavigationBar, who change the currently displayed content.
When I tap on a tab, the content updates to the new content, but the tabs icon doesn't change.
I have tried to change the BottomNavigationBarType but that changes nothing...
here is base page widget:
class Home extends StatefulWidget {
Home({Key key}) : super(key: key);
#override
_Home createState() => _Home();
}
class _Home extends State<Home> {
int _selectedIndex = 0;
static List<Widget> _widgetOptions = <Widget>[
HomePage(),
CreateTrain(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
print(_selectedIndex);
return Scaffold(
body: _widgetOptions.elementAt(_selectedIndex),
bottomNavigationBar: BottomNavigationBar(
currentIndex: 0, // this will be set when a new tab is tapped
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text('Home'),
),
BottomNavigationBarItem(
icon: new Icon(Icons.assignment),
title: new Text('Training'),
),
BottomNavigationBarItem(
icon: new Icon(Icons.play_arrow),
title: new Text('start'),
),
BottomNavigationBarItem(
icon: new Icon(Icons.insert_chart),
title: new Text('Stats'),
),
BottomNavigationBarItem(
icon: Icon(Icons.person), title: Text('Profile'))
],
selectedFontSize: 12,
unselectedFontSize: 12,
selectedItemColor: Colors.amber[800],
unselectedItemColor: Colors.grey[500],
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
onTap: _onItemTapped,
),
);
}
}
Here is HomePage widget:
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true,
title: const Text(
'Home',
style: TextStyle(
color: Colors.black,
fontSize: 30,
),
),
backgroundColor: _bgColor,
),
body: Text('data'),
);
}
}
Thanks for your help.

In your code
currentIndex: 0, // this will be set when a new tab is tapped
This should be
currentIndex: _selectedIndex, // this will be set when a new tab is tapped

Related

How to add sliding transition animation to IndexedStack?

I'm working with IndexedStack and I would like to add a sliding transition animation when the page is changed with the Bottom Navigation Bar (NOT fade animation).
This is an abstract of my code:
class _LoggedHandleState extends State<LoggedHandle> {
int _selectedPage = 1;
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("title"),
),
bottomNavigationBar: BottomNavigationBar(
unselectedItemColor: Colors.white60,
backgroundColor: Colors.red,
selectedItemColor: Colors.white,
currentIndex: _selectedPage,
onTap: (int index) {
setState(() {
_selectedPage = index;
});
},
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Hello',
),
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
label: 'Account',
),
]),
body: IndexedStack(
index: _selectedPage,
children: [HelloView(), HomeView(), UserView()],
),
);
}
}
PS: I need to use IndexedStack in order to mantain the state, so I can't use PageBuilder
At the end of the day, IndexedStack is just a Stack of elements that will show the current tab on top. To achieve what you want I'd suggest to do something similar, yet different, like this:
class LoggedHandle extends StatefulWidget {
final _pages = <Widget>[HelloView(), HomeView(), UserView()];
#override
State<StatefulWidget> createState() => _LoggedHandleState();
}
class _LoggedHandleState extends State<LoggedHandle> {
var _selectedPage = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('title'),
),
bottomNavigationBar: BottomNavigationBar(
unselectedItemColor: Colors.white60,
backgroundColor: Colors.red,
selectedItemColor: Colors.white,
currentIndex: _selectedPage,
onTap: (i) {
setState(() {
_selectedPage = i;
});
},
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Hello',
),
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
label: 'Account',
),
],
),
body: widget._pages[_selectedPage],
);
}
}
Then, for the animation, there's a Widget for that (AnimatedSwitcher). By exploiting that, along with an AnimatedWidget of your choice (or a custom one), you'll be good to go.
body: AnimatedSwitcher(
duration: const Duration(milliseconds: 650),
transitionBuilder: (child, animation) =>
ScaleTransition(scale: animation, child: child),
child: widget._pages[_selectedPage],
),

Flutter BottomNavigationBar not clickable when treated as a child widget in a separate file

I am working on this flutter app, and trying to separate some code to make things neat. So I have a home page, which contains an app bar with a tab bar inside it (works perfectly), the tab view body (works fine), and a bottom navigation bar (not working: somehow not clickable).
My footBar.dart:
import 'package:flutter/material.dart';
class FootBar extends StatefulWidget {
#override
_FootBarState createState() => _FootBarState();
}
class _FootBarState extends State<FootBar> {
int _currentIndex = 0;
Widget build(BuildContext context) {
return Container(
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
backgroundColor: Colors.white,
selectedItemColor: Colors.black,
unselectedItemColor: Colors.black.withOpacity(.3),
selectedFontSize: 14,
unselectedFontSize: 14,
showSelectedLabels: false,
showUnselectedLabels: false,
onTap: (value) {
// Respond to item press.
setState(() => _currentIndex = value);
},
items: [
BottomNavigationBarItem(
label: '',
icon: Text('a'),
),
BottomNavigationBarItem(
label: '',
icon: Text('b'),
),
BottomNavigationBarItem(
label: '',
icon: Text('c'),
),
BottomNavigationBarItem(
label: '',
icon: Text('d'),
),
],
),
);
}
}
and I imported it in homepage.dart like this:
import 'package:flutter/material.dart';
import 'appbar/appBar.dart';
import 'footbar/footBar.dart';
void main() => runApp(HomePage());
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: TopAppBar(),
body: TabBarView(
children: [
Center(child: Text('DOGS')),
Center(child: Text('CATS')),
],
),
bottomNavigationBar: FootBar(),
),
);
}
}
Any help is appreciated. Thanks in advance guys!
Okey I just found out what went wrong. So in my footBar.dart file, I should not have this:
showSelectedLabels: false,
showUnselectedLabels: false,
I commented those two lines, and put text into label, and use a 0.0 height container to hide the icons(icons: Container(height: 0.0,),), and finally got what I wanted.

Flutter: "Multiple GlobalKeys in the Widget tree" while Navigation

I'm facing an issue of "Multiple GlobalKeys in the Widget tree" while Navigation.
I have a BottomNavigationBar & a Drawer defined in the Scaffold of a Base Screen and in the body parameter of Scaffold I have multiple screens which I'm accessing with BottomNavigationBar. The thing is, I'm accessing the Drawer of the Base Screen from one of the multiple screens by using a GlobalKey, and everything's working fine but when I Navigate to the Base Screen from Another Screen then I get the above-mentioned error.
I have tried a solution of not using a static keyword while defining the key and it solves the error of navigation but then I can't access the Drawer because then I get another error of "method 'openDrawer' was called on null".
This is a separate class where I have defined the Key:
class AppKeys {
final GlobalKey<ScaffoldState> homeKey = GlobalKey<ScaffoldState>();
}
This is the Base Screen:
class Base extends StatefulWidget {
#override
_BaseState createState() => _BaseState();
}
class _BaseState extends State<Base> {
int selectedScreen = 0;
final screens = List<Widget>.unmodifiable([Home(), Cart(), Orders(), Help()]);
AppKeys appKeys = AppKeys();
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: MyDrawer(),
key: appKeys.homeKey,
body: screens[selectedScreen],
bottomNavigationBar: SizedBox(
height: 80,
child: BottomNavigationBar(
onTap: (val) {
setState(() {
selectedScreen = val;
});
},
currentIndex: selectedScreen,
selectedItemColor: AppColor.primary,
elevation: 20.0,
unselectedItemColor: Colors.grey,
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
iconSize: 25,
selectedFontSize: 15,
unselectedFontSize: 15,
items: [
BottomNavigationBarItem(
icon: Icon(AnanasIcons.home), title: Text("Home")),
BottomNavigationBarItem(
icon: Icon(AnanasIcons.cart), title: Text("Cart")),
BottomNavigationBarItem(
icon: Icon(AnanasIcons.orders), title: Text("My Orders")),
BottomNavigationBarItem(
icon: Icon(AnanasIcons.help), title: Text("Help")),
],
),
),
);
}
}
This is the Home Screen from where I'm accessing the Drawer:
class Home extends StatelessWidget {
final AppKeys appKeys = AppKeys();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(
AnanasIcons.menu,
color: Colors.black,
),
onPressed: () {
appKeys.homeKey.currentState.openDrawer();
}),
backgroundColor: Theme.of(context).canvasColor,
title: Text("Hi"),
actions: [
IconButton(
icon: Icon(
Icons.person,
color: Colors.black,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Profile(),
));
})
],
),
body: Container(),
);
}
}
I've found the answer! Instead of pushing the route with the key, we need to remove all the routes from the stack till the screen where we have to go.
Here's the code for that:
Navigator.of(context).popUntil(ModalRoute.withName(Base.routeName));

Flutter BottomNavigationBar: why selected item shifts other icons?

I'm new to flutter and I created a BottomNavigationBar and add into it some BottomNavigationBarItem that contains flutter icons.
The problem is that, when I select one item of my BottomNavigationBar, this item shifts other icons.
this is a screenshot of my app:
is there a way to block this shift ?
my code:
import 'package:flutter/material.dart';
class Navbar extends StatefulWidget {
const Navbar({ Key key }) : super(key: key);
#override
_NavbarState createState() => _NavbarState();
}
class _NavbarState extends State<Navbar> {
int index = 0;
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
iconSize: 30,
showSelectedLabels: false,
showUnselectedLabels: false,
selectedItemColor: Colors.blueGrey,
unselectedItemColor: Colors.black,
currentIndex: index,
onTap: (int selectedIndex) {
setState(() {
index = selectedIndex;
});
},
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.add,
),
title: Text('Add')
),
BottomNavigationBarItem(
icon: Icon(
Icons.favorite,
),
title: Text('Add')
),
BottomNavigationBarItem(
icon: Icon(
Icons.account_circle,
),
title: Text('Account')
)
],
);
}
}
You can change this behavior of the BottomNavigationBar by setting its type parameter to BottomNavigationBarType.fixed when constructing it.
BottomNavigationBar(
...
type: BottomNavigationBarType.fixed,
...
}
According to the documentation the default type is fixed if there are four or less items and shifting if there are more.

Set color on active item in a BottomNavigationBarType.fixed

I have a fixed BottomNavigationBar with 4 items as described below.
How can I set the color of the selected item?
I've tried with: fixedColor and selectedItemColor but it would't work.
BottomNavigationBar(
type: BottomNavigationBarType.fixed,
fixedColor: Colors.blue,
//selectedItemColor: Colors.blue,
currentIndex: snapshot.data.index,
onTap: _bottomNavBarBloc.pickItem,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.access_time,
color: Colors.black,
),
),
BottomNavigationBarItem(...),
BottomNavigationBarItem(...),
BottomNavigationBarItem(...),
]);
You can provide a different icon for Active and Normal Bottom Navigation Item.
BottomNavigationBarItem _getNavigationItem(IconData icon, String title) {
return BottomNavigationBarItem(
backgroundColor: Colors.white,
activeIcon: Icon(
icon,
color: Colors.teal,
),
icon: Icon(icon, color: Colors.grey),
title: Text(title),
);
}
There are two types available. fixed or shifting. If we add fixed type , the buttons inside bottom navigation does not show any effect when use click a particular button. It just keep fixed to the bottom navigation. If we add shifting , it will show some kind of cool animation when we click a particular button.
Check this out here
A workaround perhaps would be something like this though:
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
home: new MyHomePage(),
));
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int currentIndex = 0;
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("StackoverFlow"),
),
body: Container(),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: currentIndex,
onTap: (index) {
setState(() {
currentIndex = index;
});
},
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.access_time,
color: currentIndex == 0? Colors.blue:Colors.black,
),
title: Container(),
),
BottomNavigationBarItem(
icon: Icon(
Icons.access_time,
color: currentIndex == 1? Colors.blue:Colors.black,
),
title: Container(),
),
]),
);
}
}