flutterdartflutter-go-routergorouter

How to navigate to first/default route of GoRouter StatefulShellBranch


I'm using a StatefulShellRoute with StatefulShellBranches as in the code below.

I would like to achieve the following: when I am inside a route in a StatefulShellBranch I want to navigate to the first/default route for that StatefulShellBranch. For example, when I have navigated to path5, from inside Widget5 I want to navigate to path4.

My use case is, I have a back button inside Widget5, and when I directly navigate to path5 (i.e. via a deep link), I want to "pop" to the first/default route within the StatefulShellBranch when the back button is pressed.

Router

router = GoRouter(
    routes: StatefulShellRoute.indexedStack(
      parentNavigatorKey: parentNavigatorKey,
      branches: [
        StatefulShellBranch(
          navigatorKey: key1,
          routes: [
            GoRoute(
              path: path1,
              pageBuilder: (context, state) {
                return Widget1();
              },
              routes: <RouteBase>[
                GoRoute(
                  path: path2,
                  pageBuilder: (context, state) {
                    return Widget2();
                  },
                ),
                GoRoute(
                  path: path3,
                  pageBuilder: (context, state) {
                    return Widget3();
                  },
                ),
              ],
            ),
          ],
        ),
        StatefulShellBranch(
          navigatorKey: key2,
          routes: [
            GoRoute(
              path: path4,
              pageBuilder: (context, state) {
                return Widget4();
              },
            ),
            GoRoute(
              path: path5,
              pageBuilder: (context, state) {
                return Widget5();
              },
            ),
          ],
        ),
      ],
    ),
    GoRoute(
      parentNavigatorKey: parentNavigatorKey,
      path: path6,
      pageBuilder: (context, state) {
        return Widget6();
      },
    ));

Widget

// Inside Widget5
class BackButton extends StatelessWidget {
  ...
  onPressed() {
    if (router.canPop()) {
      router.pop();
    } else {
      // TODO: Navigate to default route of StatefulShellBranch
      final defaultRoute = router
          .routerDelegate
          .currentConfiguration.???();
    }
  }
  ...
}

Solution

  • In my case, I set up the StatefulShellBranch this way:

    class Dashboard extends StatefulWidget {
      final StatefulNavigationShell navigationShell;
      const Dashboard({required this.navigationShell, super.key});
    
      @override
      State<Dashboard> createState() => _DashboardState();
    }
    ...
    

    Note that the Dashboard class monitors the bottomAppBarIndex changes, since it resides within that class.

    I used it in my PopScope logic, where it could mimic the way onPressed: () => works (i.e., in your POV, of course).

    WidgetsBinding.instance.addPostFrameCallback((_) {
      widget.navigationShell.goBranch(
        0,
        initialLocation: bottomAppBarIndex ==
            widget.navigationShell.currentIndex,
      );
    });
    

    In my use case, I am using bottomAppBarIndex, which is created with Riverpod's Provider to handle state management and synchronize with the bottomNavigationBar's index changes.

    I hope this provides a reference that you can replicate in your case, so you need to change the index of parentNavigatorKey to 0. Does this make sense to you?

    How to implement it in multiple instance of StatefulShellBranch?

    The challenge you can overcome is on how to pass it through the Widget5 class.