4

I'm trying to setup a multipage app in Flutter, where the bottom tabbar contains the four most used pages, including a "More" button. The more button shows a page with links to other pages. When clicking on a page, I want this page to replace the "More" page, so a new navigation stack is created. However, when switching to another tab and then back to the "more" tab, the navigation state is remembered. This means I'm not seeing the "More" page, but the page I left when switching tabs. I want to show the "More" page everytime the user clicks on the "More" tab.

I've tried using the pushReplacement method of the Navigator, so when the user clicks on a more-page, he can't navigate back to the list of more pages. However, when switching tabs, the more page is now never shown, because it's replaced.

I've also tried adjusting the tab callback method, to pop all views and return the navigator to the MoreScreen. However, this left me with an error in the console: setState() or markNeedsBuild() called during build..

The tab screen:

class TabScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return TabScreenState();
  }
}

class TabScreenState extends State<TabScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: WillPopScope(
        // Prevent swipe popping of this page. Use explicit exit buttons only.
        onWillPop: () => Future<bool>.value(true),
        child: CupertinoTabScaffold(
          tabBar: CupertinoTabBar(
            items: const <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                icon: Icon(Icons.home),
                title: Text('Artikelen'),
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.message),
                title: Text('Activiteiten'),
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.speaker_group),
                title: Text('Training'),
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.more),
                title: Text('Meer'),
              ),
            ],
          ),
          tabBuilder: (BuildContext context, int index) {
            assert(index >= 0 && index <= 3);
            switch (index) {
              case 0:
                return CupertinoTabView(
                  builder: (BuildContext context) {
                    Navigator.of(context).popUntil((route) => route.isFirst);

                    return ArticleListScreen();
                  },
                  defaultTitle: 'Artikelen',
                );
                break;
              case 1:
                return CupertinoTabView(
                  builder: (BuildContext context) => ActivityListScreen(),
                  defaultTitle: 'Activiteiten',
                );
                break;
              case 2:
                return CupertinoTabView(
                  builder: (BuildContext context) => ArticleListScreen(),
                  defaultTitle: 'Training',
                );
                break;
              case 3:
                return CupertinoTabView(
                  builder: (BuildContext context) {
                    Navigator.of(context).popUntil((route) => route.isFirst);

                    return MoreScreen();
                  },
                  defaultTitle: 'Meer',
                );
                break;
            }
            return null;
          },
        ),
      ),
    );
  }
}

And the MoreScreen which holds a button to go to another page:

class MoreScreen extends StatefulWidget {
  @override 
  State<StatefulWidget> createState() {
    return MoreScreenState();
  }
}

class MoreScreenState extends State<MoreScreen> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: ThemeData.dark().accentColor,
        alignment: AlignmentDirectional(0.0, 0.0),
        child: MaterialButton(
          child: Text('PUSH page'),
          onPressed: () => {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => ArticleListScreen()))
          },
        )
      ),
    );
  }
}

I expect the navigation stack to reset everytime I switch tabs, but now I have to do that manually using:

Navigator.of(context).popUntil((route) => route.isFirst);

This leads to the error message: setState() or markNeedsBuild() called during build. after pushing a new page in a tab and then switching tabs.

Thomas Roovers
  • 116
  • 2
  • 9

0 Answers0