3

I have a bottom navigation bar widget for my Flutter app. On tapping specific item it is navigating to another screen. However, I don't know how to update current index in this case so that selected tab gets highlighted. Here is my code:

        BottomNavigationBar(
          backgroundColor: const Color(0xffFF7B19),
          items: <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              icon: Icon(
                Icons.calendar_today_rounded,
                size: lh / 25,
              ),
              label: 'Events',
            ),
            BottomNavigationBarItem(
              icon: Icon(
                Icons.people_alt_outlined,
                size: lh / 25,
              ),
              label: 'Councils',
            ),
          ],
          currentIndex: 0,
          selectedItemColor: Colors.grey[900],
          unselectedItemColor: Colors.grey[50],
          onTap: (int index) {
            if (index == 0) {
              Navigator.push(context,
                  MaterialPageRoute(builder: (context) => AllEventsScreen()));
            } else {
              Navigator.push(
                  context, MaterialPageRoute(builder: (context) => Councils()));
            }
          })

Here is the output

I have tried creating a variable _selectedIndex for this which I was updating inside the function I have provided for onTap as shown:

          currentIndex: _selectedIndex,
          selectedItemColor: Colors.grey[900],
          unselectedItemColor: Colors.grey[50],
          onTap: (int index) {
            if (index == 0) {
              Navigator.push(context,
                  MaterialPageRoute(builder: (context) => AllEventsScreen()));
              _selectedIndex = 0;
            } else {
              Navigator.push(
                  context, MaterialPageRoute(builder: (context) => Councils()));
              _selectedIndex = 1;
            }

But this doesn't seems to work. I couldn't figure out how to do this.

enggPS
  • 686
  • 1
  • 7
  • 23

3 Answers3

1

Use the _selectedIndex with a PageView and set the onTap like this :

          currentIndex: _selectedIndex,
          selectedItemColor: Colors.grey[900],
          unselectedItemColor: Colors.grey[50],
          onTap: (int index) {
              setState(()=>_selectedIndex=index);
            }

Reading this article would be helpful

Edit: This is a full example

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _selectedIndex = 0;
  late PageController _pageController;
  @override
  void initState() {
    super.initState();
    _pageController = PageController(
      initialPage: _selectedIndex,
    );
  }

  Widget build(BuildContext context) {
    return Scaffold(
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: _selectedIndex,
          onTap: (index) {
            setState(() {
              _selectedIndex = index;
              _pageController.animateToPage(index,
                  duration: Duration(milliseconds: 500), curve: Curves.ease);
            });
          },
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: "Home",
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.search),
              label: "Search",
            ),
          ],
        ),
        appBar: AppBar(
          title: Text('Test App'),
        ),
        body: PageView(
          controller: _pageController,
          onPageChanged: (index) {
            setState(() {
              _selectedIndex = index;
            });
          },
          children: [
            Container(
              color: Colors.red,
              child: Center(
                child: Text("Home"),
              ),
            ),
            Container(
              color: Colors.green,
              child: Center(
                child: Text("Search"),
              ),
            ),
          ],
        ));
  }
}
Youssef Elmoumen
  • 468
  • 4
  • 10
  • adding setState() method doesn't seems to work properly. It may be changing the current index but that becomes visible after navigating again to the original screen and not changing when it is clicked. – enggPS Feb 13 '22 at 16:40
  • If you want to save the state of the selected index use Provider or Bloc for state management – Youssef Elmoumen Feb 13 '22 at 17:10
0

You could go with the first answer or you could go with TabBarView

return DefaultTabController(
  length: 2,
  child: Scaffold(
    body: TabBarView(
      children: [
        Container(),
        Container()
      ]
    ),
    bottomNavigationBar: TabBar(
      tabs: [
          GestureDetector(
            onTap: () {
              Navigator.push(context,
                MaterialPageRoute(builder: (context) => AllEventsScreen()));
            },
            child: Tab(
              icon: Icon(
                Icons.calendar_today_rounded,
                size: lh / 25,
              ),
              text: 'Events',
            ),
          ),
          GestureDetector(
            onTap: () {
              Navigator.push(
                context, MaterialPageRoute(builder: (context) => Councils()));
            },
            child: Tab(
              icon: Icon(
                Icons.people_alt_outlined,
                size: lh / 25,
              ),
              text: 'Councils',
            ),
          )]
    )
  ),
);
Rohith Nambiar
  • 2,957
  • 4
  • 17
  • 37
0

it's been 1 year, but i ran with the same situation, i've been trying to solve it , the main points are:

  1. Create the bottom bar with screens

  2. update the index accordingly

  3. save the state of the index

Basic bottom Nav bar with design

```
  final PageController _controller = PageController();
  final int _currentIndex = 0;

  final List<Widget> _screens = const [
    Home(),
    Screen2(),
    Screen3()
  ];
  
  void onTap(int index) {
    _controller.jumpToPage(index);
  }

  @override
  Widget build(BuildContext context) {
     return Scaffold(
       bottomNavigationBar: BottomNavigationBar(
       type: BottomNavigationBarType.fixed,
       backgroundColor: Colors.white,
       selectedLabelStyle: const TextStyle(color: Colors.black),
       selectedItemColor: Colors.yellow,
       unselectedItemColor: Colors.black54,
       showUnselectedLabels: true,
       showSelectedLabels: true,
       elevation: 3,
       currentIndex: _currentIndex,
       onTap: (index) {
        _controller.jumpToPage(index);
        setState(() {
         _currentIndex = index;
        });
       },
       items: [
         BottomNavigationBarItem(
          label: "Home"),
         BottomNavigationBarItem(
          label: "screen2"),
         BottomNavigationBarItem(
          label: "screen3"),
       ],
      ),
    body: PageView(
     physics: const NeverScrollableScrollPhysics(),
     controller: _controller,
     children: _screens,
   ),
);}

For saving the state of the current index, i wrapped a Stack with the PageView!

  Stack(
        children: [
          PageView(
            physics: const NeverScrollableScrollPhysics(),
            controller: _controller,
            children: _screens,
          ),
        ],
      )

This is the trick, i hope it will work with you as well!

Hanana
  • 31
  • 5