Flutter: How to change the FloatingactionButton icon in the BottomNavBar when pressed?

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)

Leave a Reply

Your email address will not be published. Required fields are marked *