Issue
I’m trying to change the icon of the FloatingActionButton() in the bottom navigation bar when clicked. It works fine but only when I leave the screen and come back? Does anyone know what’s wrong? Setstate in the changeIcon() is called which should force a rerendering, or am I wrong?
I would really appreciate some help 🙂
Edit:
It doesnt even work if I put in the if this.pressed
bool statement as child. The state of the this.pressed
flag is changed from false to true (printed the state) but even this does not lead the button to change its icon.
return FloatingActionButton(
child: this.pressed ? Icon(Icons.people) : Icon(Icons.close),
onPressed: () {
changeIcon();
});
The code is attached here:
class HomeState extends State<Home> {
MapRadials buttonProvider;
Icon fabIcon = Icon(Icons.perm_media);
FloatingActionButton floatingActionButton;
int _currentIndex = 0;
List<Widget> _screens = [
FeedScreen(),
MapScreen(),
MapScreen(),
NotificationScreen(),
ChatScreen(),
];
@override
void initState() {
super.initState();
floatingActionButton = FloatingActionButton(
onPressed: () {},
child: fabIcon,
);
}
void changeIcon(Icon icon) {
setState(() {
fabIcon = icon;
});
}
@override
Widget build(BuildContext context) {
final MapRadials radialProvider = Provider.of<MapRadials>(context);
this.buttonProvider = radialProvider;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: IconButton(
icon: Icon(
Icons.menu,
size: 30.0,
color: Colors.black,
),
onPressed: () {},
),
actions: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
IconButton(
icon: Icon(
Icons.filter_list,
size: 30.0,
color: Colors.black,
),
onPressed: () {},
),
IconButton(
icon: Icon(
Icons.search,
size: 30.0,
color: Colors.black,
),
onPressed: () {},
),
],
)
],
)
],
),
bottomNavigationBar: bottomNavBar(),
floatingActionButton: this.floatingActionButton,
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
body: _screens[_currentIndex],
);
}
void onTabTapped(int index) {
setState(() {
if (index != 2) {
_currentIndex = index;
floatingActionButton = getFloatingActionButton(index);
}
});
}
Widget getFloatingActionButton(int index) {
switch (index) {
case 0: // Home
return FloatingActionButton(child: Icon(Icons.add), onPressed: () {});
case 1: // Map
return FloatingActionButton(
child: fabIcon,
onPressed: () {
changeIcon(Icon(Icons.save));
});
case 2: // Notification
return FloatingActionButton(
child: Icon(Icons.clear_all), onPressed: () {});
case 3: // Chat
return FloatingActionButton(
child: Icon(Icons.add_comment), onPressed: () {});
default:
return FloatingActionButton(child: Icon(Icons.add), onPressed: () {});
}
}
Widget bottomNavBar() {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: onTabTapped,
currentIndex: _currentIndex,
showSelectedLabels: false,
showUnselectedLabels: false,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
color: Colors.black,
),
title: Text('Feed'),
),
BottomNavigationBarItem(
icon: Icon(
Icons.person_pin_circle,
color: Colors.black,
),
title: Text('Map')),
BottomNavigationBarItem(
icon: Icon(
null,
),
title: Text('Placeholder')),
BottomNavigationBarItem(
icon: Icon(
Icons.notifications,
color: Colors.black,
),
title: Text('Noftications'),
),
BottomNavigationBarItem(
icon: Icon(
Icons.chat_bubble,
color: Colors.black,
),
title: Text('Chat'))
],
);
}
}
Solution
You are changing the icon in the state and using setState()
for it, and that is fine, but notice that setState()
is rebuilding your widget tree with a Scaffold
whose floatingActionButton
parameter is floatingActionButton: this.floatingActionButton
, and you are setting your this.floatingActionButton
in the initState()
method, that will be called only once (whenever the whole Widget is instantiated). Since that this.floatingActionButton
is only being instantiated once with the initial icon, the rebuild triggered by setState()
does not render the FAB with the new icon.
Try setting your this.floatingActionButton
in didChangeDependencies()
instead of initState()
, since, according to the flutter.dev documentation article on didChangeDependecies, it will be
Called when a dependency of this State object changes.
Answered By – drogel
Answer Checked By – Timothy Miller (FlutterFixes Admin)