Problem with Navigation (Error: RangeError (index): Index out of range: index should be less than 3: 3)

Issue

I am trying to create custom Navigation for my flutter app, the app and the navigation works fine until there are 3 screens/pages. As soon as I add the 4th Screen, I get a range error the error stack is the following:

 ======== Exception caught by gesture ===============================================================
The following IndexError was thrown while handling a gesture:
RangeError (index): Index out of range: index should be less than 3: 3

When the exception was thrown, this was the stack: 
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49  throw_
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/js_array.dart 581:7             _get]
packages/test_proj/page_navigator.dart 17:35                                                                               <fn>
packages/flutter/src/material/bottom_navigation_bar.dart 987:25                                                            <fn>
packages/flutter/src/material/ink_well.dart 989:21                                                                         [_handleTap]
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#86634
  debugOwner: GestureDetector
  state: ready
  won arena
  finalPosition: Offset(908.8, 678.4)
  finalLocalPosition: Offset(131.8, 5.4)
  button: 1
  sent tap down
====================================================================================================

As soon as I add the fourth page, I also stop getting an output of my screen on my Third page. This is the code:

    class App extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => AppState();
}

class AppState extends State<App> {
  String _currentPage = "Page1";
  List<String> pageKeys = ["Page1", "Page2", "Page3, Page4"];
  Map<String, GlobalKey<NavigatorState>> _navigatorKeys = {
    "Page1": GlobalKey<NavigatorState>(),
    "Page2": GlobalKey<NavigatorState>(),
    "Page3": GlobalKey<NavigatorState>(),
    "Page4": GlobalKey<NavigatorState>(),
  };
  int _selectedIndex = 0;


  void _selectTab(String tabItem, int index) {
    if(tabItem == _currentPage ){
      _navigatorKeys[tabItem]!.currentState!.popUntil((route) => route.isFirst);
    } else {
      setState(() {
        _currentPage = pageKeys[index];
        _selectedIndex = index;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        final isFirstRouteInCurrentTab =
        !await _navigatorKeys[_currentPage]!.currentState!.maybePop();
        if (isFirstRouteInCurrentTab) {
          if (_currentPage != "Page1") {
            _selectTab("Page1", 1);

            return false;
          }
        }
        // let system handle back button if we're on the first route
        return isFirstRouteInCurrentTab;
      },
      child: Scaffold(
        body: Stack(
            children:<Widget>[
              _buildOffstageNavigator("Page1"),
              _buildOffstageNavigator("Page2"),
              _buildOffstageNavigator("Page3"),
              _buildOffstageNavigator("Page4"),
            ]
        ),
        bottomNavigationBar: BottomNavigationBar(
          selectedItemColor: Colors.blueAccent,
          onTap: (int index) { _selectTab(pageKeys[index], index); },
          currentIndex: _selectedIndex,
          items: [
            BottomNavigationBarItem(
              icon: new Icon(Icons.looks_one),
              label: 'Page1'
            ),
            BottomNavigationBarItem(
              icon: new Icon(Icons.looks_two),
              label: 'Page2'
            ),
            BottomNavigationBarItem(
              icon: new Icon(Icons.looks_3),
              label: 'Page3'
            ),
            BottomNavigationBarItem(
              icon: new Icon(Icons.looks_4),
              label: 'Page4'
            ),
          ],
          type: BottomNavigationBarType.fixed,
        ),
      ),
      );

  }



  Widget _buildOffstageNavigator(String tabItem) {
    return Offstage(
      offstage: _currentPage != tabItem,
      child: TabNavigator(
        navigatorKey: _navigatorKeys[tabItem]!,
        tabItem: tabItem,
      ),
    );
  }
}

and….

class TabNavigatorRoutes {
  static const String root = '/';
  static const String detail = '/detail';
}

class TabNavigator extends StatelessWidget {
  TabNavigator({required this.navigatorKey, required this.tabItem});
  final GlobalKey<NavigatorState> navigatorKey;
  final String tabItem;

  @override
  Widget build(BuildContext context) {

    Widget child = Text("plz work");
    if(tabItem == "Page1")
      child = Page1();
    else if(tabItem == "Page2")
      child = Page2();
    else if(tabItem == "Page3")
      child = Page3();
    else if(tabItem == "Page4")
      child = Page4();

    return Navigator(
      key: navigatorKey,
      onGenerateRoute: (routeSettings) {
        return MaterialPageRoute(
            builder: (context) => child
        );
      },
    );
  }
}

As for the actual content on the pages, It is just a Text widget. Please help me if possible. Thanks.

Solution

The last two indexes seems to be joined to a single String. That’s why the max index is 3 instead of the expected 4 – pointed on the error thrown: "RangeError (index): Index out of range: index should be less than 3: 3"

List<String> pageKeys = ["Page1", "Page2", "Page3, Page4"];

This should be

List<String> pageKeys = ['Page1', 'Page2', 'Page3', 'Page4'];

Answered By – Omatt

Answer Checked By – Clifford M. (FlutterFixes Volunteer)

Leave a Reply

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