Search code examples
flutterbottom-navigation-bar

Why doesn't BottomNavigatorBarItem currentIndex get updated?


I am new to flutter and I did find similar questions on SO but am too novice to understand the nuance so apologies if this question is too similar to an already asked one.

I have a BottomNavigationBar which has 3 icons (Home, Play and Create) which should navigate between these 3 routes/pages.

main.dart

routes: {
  "/home": (context) => MyHomePage(title: "STFU"),
  "/play": (context) => Play(),
  "/create": (context) => Create(),
  "/settings": (context) => Settings(),
},

I extracted my navbar into a custom class so my 3 separate pages could use it:

bottom-nav.dart

class MyBottomNavBar extends StatefulWidget {
  MyBottomNavBar({
    Key? key,
  }) : super(key: key);

  @override
  State<MyBottomNavBar> createState() => _MyBottomNavBarState();
}

class _MyBottomNavBarState extends State<MyBottomNavBar> {
  int _selectedIndex = 0;

  void _onTapped(int index) => {
        print("_onTapped called with index = $index"),
        setState(
          () => _selectedIndex = index,
        )
      };

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      backgroundColor: Colors.orangeAccent[100],
      currentIndex: _selectedIndex,
      onTap: (value) => {
        print("value is $value"),
        // find index and push that
        _onTapped(value),
        if (value == 0)
          {Navigator.pushNamed(context, "/home")}
        else if (value == 1)
          {Navigator.pushNamed(context, "/play")}
        else if (value == 2)
          {Navigator.pushNamed(context, "/create")}
      },
      items: [
        BottomNavigationBarItem(label: "Home", icon: Icon(Icons.home_filled)),
        BottomNavigationBarItem(
            label: "Play", icon: Icon(Icons.play_arrow_rounded)),
        BottomNavigationBarItem(label: "Create", icon: Icon(Icons.create)),
      ],
    );
  }
}

so now i just set this MyBottomNavBar class to the bottomNavigationBar property of the Scaffold widget my inside Home page, Play page and Create page for eg.

home.dart

class _MyHomePageState extends State<MyHomePage> {
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Home"),
      ),
      body: Column(
        children: [
          Container(
            padding: EdgeInsets.all(20.00),
            child: Text("inside home"),
          ),
        ],
      ),
      bottomNavigationBar: MyBottomNavBar(),
    );
  }
}

play.dart

class Play extends StatefulWidget {
  const Play({super.key});

  @override
  State<Play> createState() => _PlayState();
}

class _PlayState extends State<Play> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Text("inside play page"),
            SizedBox(
              height: 30.00,
            ),
            Text("some text"),
          ],
        ),
      ),
      bottomNavigationBar: MyBottomNavBar(),
    );
  }
}

The nav bar buttons work to switch between pages but for some reason the currentIndex value isn't getting updated and stays at 0 (i.e on the "Home" icon). When I debug it I can see _selectedIndex getting updated inside inside the _onTapped function which should update the currentIndex value but it doesn't appear to do so. Any help would be appreciated


Solution

  • What you have here is three different pages with their separate BottomNavBar class instance. Instead you should have a shared Scaffold and one bottomNavBar so that when you navigate bottomNavbar state does not reset.

    You can use PageView to do this.

    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key});
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      void initState() {
        super.initState();
      }
    
      List<Widget> pages = const [Home(), Play(), Create()];
      final _pageController = PageController();
      int _selectedIndex = 0;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          bottomNavigationBar: BottomNavigationBar(
            currentIndex: _selectedIndex,
            onTap: (index) {
              _pageController.jumpToPage(index);
              _selectedIndex = index;
              setState(() {});
            },
            items: const [
              BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
              BottomNavigationBarItem(icon: Icon(Icons.play_arrow), label: 'Play'),
              BottomNavigationBarItem(icon: Icon(Icons.create), label: 'Create'),
            ],
            backgroundColor: Colors.greenAccent,
          ),
          body: PageView(
            controller: _pageController,
            children: pages,
          ),
        );
      }
    }
    
    class Home extends StatelessWidget {
      const Home({super.key});
    
      @override
      Widget build(BuildContext context) {
        return const Placeholder();
      }
    }
    
    class Play extends StatelessWidget {
      const Play({super.key});
    
      @override
      Widget build(BuildContext context) {
        return const Placeholder();
      }
    }
    
    class Create extends StatelessWidget {
      const Create({super.key});
    
      @override
      Widget build(BuildContext context) {
        return const Placeholder();
      }
    }