0

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

amy
  • 354
  • 1
  • 9

1 Answers1

0

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();
  }
}
Soliev
  • 1,180
  • 1
  • 1
  • 12
  • Thank you, but this doesn't run unfortunately, a lot of exceptions are generated: ═══════ Exception caught by gesture ═══════════════════════════════════════════ The following assertion was thrown while handling a gesture: ScrollController not attached to any scroll views. 'package:flutter/src/widgets/scroll_controller.dart': package:flutter/…/widgets/scroll_controller.dart:1 Failed assertion: line 107 pos 12: '_positions.isNotEmpty' – amy Jan 31 '23 at 18:21
  • I tested it's working as expected. Can I see your implementation? – Soliev Jan 31 '23 at 23:33
  • Hi @Soliev, sure, [here it is](https://pastebin.com/HcCZFPCA) If I remove the PageView widget from the body and comment out the `_pageController.jumpToPage(index);` line in the `onTap` function, then the app does at least build, so something about adding this it doesn't like – amy Feb 01 '23 at 13:28
  • ` List pages = const [Home(), Play(), Create()]` inside pages you cannot have `Home()` class nested inside itself. – Soliev Feb 01 '23 at 23:43
  • Thanks! this was indeed the issue. Not to shift blame lol but the error logs for this were indecipherable (or i'm too much of a flutter noob to understand them) – amy Feb 04 '23 at 14:38