Change tab on BottomNavigationBar Flutter programmatically and without using onTap of BottomNavigationBar?

Issue

I am working on a flutter application where I need to redirect to the first screen on BottomNavigationBar when the user presses back from any other screen of the remaining BottomNavigationBar screens. For now, I have added redirecting event on a simple button, will replace this on _onWillPop event.

Please find the code below:

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {

  final PageStorageBucket bucket = PageStorageBucket();

  Widget currentScreen = HomeFragment();
  int currentTab = 0;

  static int selectedIndexN = 0;
  static const TextStyle optionStyle = TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
  List<Widget> _widgetOptions1 = <Widget>[
    HomeFragment(),
    LoginFargment(),
    SignUpFargment(),
    ProfileFargment(),
  ];

  void changeTabMethod(int index) {
    print('changeTabMethod is called');
    setState(() {
      selectedIndexN = index;
    });
    print('changeTabMethod is called : selectedIndexN : $selectedIndexN');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // return GetBuilder<DashboardController>(
      body: Center(
        child: _widgetOptions1.elementAt(selectedIndexN),
      ),
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: selectedIndexN,
        onTap: changeTabMethod,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Login',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'SignUp',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}

Profile screen code:

class ProfileFargment extends StatefulWidget {
  @override
  _ProfileFragmentState createState() => _ProfileFragmentState();
}

class _ProfileFragmentState extends State<ProfileFargment> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body:SafeArea(
          child: Container(
            padding: EdgeInsets.all(20.0),
            height: double.infinity,
            width: double.infinity,
            color: Colors.teal,
            child: GestureDetector(
                  onTap: () {
                    //Calling method changeTabMethod(0)
                    HomeScreen().createState().changeTabMethod(0);
                  },
                  child: Container(
                    margin: EdgeInsets.only(top: 20.0),
                    height: 40.0,
                    width: 150.0,
                    color: Colors.white,
                    child: Center(child: Text('Profile'),),
                  ),
                ),
        ),
      ),
    );
  }
}

On the other hand, when I call changeTabMethod from a ProfileFragment screen, it will enter into changeTabMethod but couldn’t execute the setState method. So my tab is not changing.

You can consider this console report:
changeTabMethod is called is only printed the second print after setState was not executed.

Can you please let me know what or where I am doing anything wrong?

Thanks in advance 🙂

Solution

Try below code. By passing function as parameter you can trigger function on home page from any other page.
Home screen code:

 class HomeScreen extends StatefulWidget {
      @override
      _HomeScreenState createState() => _HomeScreenState();
    }
    
    class _HomeScreenState extends State<HomeScreen> {
      final PageStorageBucket bucket = PageStorageBucket();
    
    //       Widget currentScreen = HomeFragment();
      int currentTab = 0;
    
      static int selectedIndexN = 0;
      static const TextStyle optionStyle =
          TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
    
      Widget _widgetOptions1(int index) {
        switch (index) {
          case 0:
            return ProfileFargment(onButtonPressed: changeTabMethod);
    
          case 1:
            return Container(child: Text("Page - 2 "));
    
          case 2:
            return Container(child: Text("Page - 3 "));
          default:
            return Container();
        }
      }
    
      void changeTabMethod(int index) {
        print('changeTabMethod is called');
        setState(() {
          selectedIndexN = index;
        });
        print('changeTabMethod is called : selectedIndexN : $selectedIndexN');
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          // return GetBuilder<DashboardController>(
          body: Center(
            child: _widgetOptions1(selectedIndexN),
          ),
          bottomNavigationBar: BottomNavigationBar(
            type: BottomNavigationBarType.fixed,
            currentIndex: selectedIndexN,
            onTap: changeTabMethod,
            items: const <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                icon: Icon(Icons.home),
                label: 'Home',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.business),
                label: 'Login',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.school),
                label: 'SignUp',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.school),
                label: 'Profile',
              ),
            ],
          ),
        );
      }
    }

Profile screen code:

class ProfileFargment extends StatefulWidget {
  final void Function(int) onButtonPressed;
  const ProfileFargment({Key key, this.onButtonPressed});
  @override
  _ProfileFragmentState createState() => _ProfileFragmentState();
}

class _ProfileFragmentState extends State<ProfileFargment> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          padding: EdgeInsets.all(20.0),
          height: double.infinity,
          width: double.infinity,
          color: Colors.teal,
          child: GestureDetector(
            onTap: () {
              //Calling method changeTabMethod(0)
              // HomeScreen().createState().changeTabMethod(0);
              widget.onButtonPressed(0);
            },
            child: Container(
              margin: EdgeInsets.only(top: 20.0),
              height: 40.0,
              width: 150.0,
              color: Colors.white,
              child: Center(
                child: Text('Profile'),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Answered By – TheAlphamerc

Answer Checked By – David Marino (FlutterFixes Volunteer)

Leave a Reply

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