Flutter – navigate back to specific tab on a page with Navigator.pop(context)

Issue

In my app, I have a homepage that has 5 tabs on the bottom. On each tabbed page, there is an app bar that has a ‘+’ symbol as an action, which navigates you to a different page. The navigation with that ‘+’ button to the new page is done with the following code, alongside the Flutter Platform Widgets package:

Navigator.of(context, rootNavigator: true)
    .push(
  platformPageRoute(
    context: context,
    builder: (context) => Page1(),
  ),
);

I use the platformPageRoute feature as an easy way to navigate with a native feel. Now, that works fine to navigate to a new page, but the issue comes when I use

Navigator.pop(context);

to navigate back to the original page. When I use that to navigate back to that original page, it pays no attention to the tab that was selected originally. For example, if I were originally on the second tab on the homepage and then use the ‘+’ button on that tab and then finally use

Navigator.pop(context);

on that new page, it returns the first tab of the homepage. Is there any way of ensuring when I use the above command, it goes to the right tab? I have tried something along the lines of:

Navigator.popUntil(context, '/homepageTab2');

alongside a named route, to return to the correct tab on the homepage, although that returns a black screen. Why might that be? I have also tried using:

              Navigator.pushAndRemoveUntil(
                context,
                platformPageRoute(
                  context: context,
                  builder: (context) =>
                      HomePage(selectedPage: 1),
                ),
                (route) => false,
              );

This does not work either, since it returns the selected/correct page tab content, but with the first tab selected. In addition, the other
‘problem’ for me is that the animation is a ‘push’ one and that doesn’t ‘match’ with the animation when I have more often used

Navigator.pop(context);

to navigate back to a screen. Is there a way to maybe use pushAndRemoveUntil but then change the animation to match a pop animation?

Thanks!

EDIT:

I have just noticed that with the situation I have described above, it is actually returning the correct screen content when I use Navigator.pop(context); but the tab in the tab bar at the bottom is showing as the first tab, in the second tab’s position, essentially duplicating the first tab, until I navigate to a new tab and back, at which time it shows the correct tab in the correct position. I hope that makes sense!

Solution

As it turns out, the issue wasn’t related to Navigator.pop(context); being used. It was the way I was controlling the selected tab. I’m posting this as an answer incase it helps someone else.

Initially, I created late values for a tab controller and the current selected page, like so:

late TabController _tabController;
late ScrollController _scrollController;
late int _selectedPage;

Then, I created a list of widgets that represented the actual page to display for each selected tab:

List<Widget> _pageWidgets = <Widget>[
  Page1();
  Page2();
  Page3();
  Page4();
  Page5();
];

Then (and I think this was the bit that wasn’t working) I used initState() as follows:

  void initState() {
    super.initState();

    // Initialising a value that allows the 'final' page selector to be changed
    _selectedPage = widget.selectedPage;

    // Initialising the tab controller
    _tabController = TabController(
      length: 5,
      vsync: this,
      initialIndex: _selectedPage,
    );

    // updating the tab index when a new item is selected
    _tabController.addListener(() {
      setState(() {
        _selectedPage = _tabController.index;
        //_tabIndex = _tabController.index;
      });
    });

    // Creating the scroll controller
    _scrollViewController = ScrollController();

    // Scrolling view to top when a new tab is selected
    _tabController.addListener(() {
      setState(() {
        _scrollViewController
            .jumpTo(_scrollViewController.position.minScrollExtent);
      });
    });
  }

I then controlled the page content like this:

body: _pageWidgets.elementAt(_selectedPage),

I’m not 100% sure why this wasn’t working, although I believe it would have something to do with the fact that initState() would only be called during the build and therefore placing the functionality inside there would mean changes wouldn’t be detected. Either way, my new method, which works perfectly, is:

  /// Controls the screen to display first
  int _index = 0;

  /// Creating a navigation key to control tab bar navigation
  final _navigationKey = GlobalKey<CurvedNavigationBarState>();

Then, within the Scaffold() I show the page content like this:

body: _pageWidgets.elementAt(_index),

And finally, within the navigation bar (which is the CurvedNavigationBar() package from pub.dev) I give it a key and the index:

key: _navigationKey,
index: _index,

And this controls it perfectly, showing the correct tab.

Answered By – James

Answer Checked By – Marie Seifert (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *