Search code examples
flutterflutter-bottomnavigation

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


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'),
                  ),
                ),
              ),
            ),
          ),
        );
      }
    }