Jay Mungara
Jay Mungara

Reputation: 7148

Flutter Web - Go Router Navigation Change Web URL based on bottom tab selection

I was trying to implement a bottom-tab navigation with 3 tabs in my home screen for my flutter website project. Currently I'm using go_router package for flutter web routing.

Following is my code for web app navigation, What I want to achieve is ontap of particular bottom tab 1 tap. I want to change the url to something like <Web_URL>/#Tab1.

But, I couldn't found anything useful. Can anyone please help?

static final List<GoRoute> _appRoutes = [
    GoRoute(
        path: AppRouter.pathLogin,
        builder: (BuildContext context, GoRouterState state) =>
            const LoginScreen()),
    GoRoute(
      path: AppRouter.pathHome,
      builder: (BuildContext context, GoRouterState state) =>
          const HomeScreen(),
      routes: [
        GoRoute(
            path: AppRouter.pathCreateContact,
            builder: (BuildContext context, GoRouterState state) =>
                const CreateContactScreen()),
      ],
    ),
  ];

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
        title: 'Follow-Up',
        debugShowCheckedModeBanner: false,
        routeInformationParser: _router.routeInformationParser,
        routeInformationProvider: _router.routeInformationProvider,
        routerDelegate: _router.routerDelegate);
  }

  final GoRouter _router = GoRouter(
      routes: _appRoutes,
      urlPathStrategy: UrlPathStrategy.path,
      initialLocation: FirebaseAuth.instance.currentUser != null
          ? AppRouter.pathHome
          : AppRouter.pathLogin);

Upvotes: -1

Views: 3624

Answers (1)

DevQt
DevQt

Reputation: 719

You can achieve that using StatefulShellRoute and StatefulShellBranch.

Create a class where your bottom tab selection are located

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class HomeNavHost extends StatelessWidget {
  const HomeNavHost({required this.navigationShell, super.key});

  final StatefulNavigationShell navigationShell;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: navigationShell,
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: navigationShell.currentIndex,
        onTap: (index) {
          WidgetsBinding.instance.addPostFrameCallback((_) {
            navigationShell.goBranch(
              index,
              initialLocation: index == navigationShell.currentIndex,
            );
          });
        },
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.dashboard),
            label: 'Dashboard',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.favorite),
            label: 'Favourites',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            label: 'Settings',
          ),
        ],
      ),
    );
  }
}

You can create a class or a simple variable instance of your GoRouter

Simplified example code snippet:

void main() {
  runApp(
    App(),
  );
}

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) =>
      MaterialApp.router(routerConfig: mainRouter);
}

final _mainKey = GlobalKey<NavigatorState>();
final _dashboardKey = GlobalKey<NavigatorState>();
final _favouritesKey = GlobalKey<NavigatorState>();
final _settingsKey = GlobalKey<NavigatorState>();
final GoRouter mainRouter = GoRouter(
  initialLocation: '/dashboard',
  navigatorKey: _mainKey,
  routes: [
    StatefulShellRoute.indexedStack(
      builder: (context, state, navigationShell) =>
          HomeNavHost(navigationShell: navigationShell),
      branches: [
        StatefulShellBranch(
          navigatorKey: _dashboardKey,
          routes: [
            GoRoute(
              path: '/dashboard',
              pageBuilder: (context, state) => NoTransitionPage(
                  key: state.pageKey, child: Center(child: Text('Dashboard'))),
            ),
          ],
        ),
        StatefulShellBranch(
          navigatorKey: _favouritesKey,
          routes: [
            GoRoute(
              path: '/favourites',
              pageBuilder: (context, state) => NoTransitionPage(
                  key: state.pageKey, child: FavouritesScreen()),
            ),
          ],
        ),
        StatefulShellBranch(
          navigatorKey: _settingsKey,
          routes: [
            GoRoute(
              path: '/settings',
              pageBuilder: (context, state) => NoTransitionPage(
                  key: state.pageKey, child: Center(child: Text('Settings'))),
            ),
          ],
        ),
      ],
    )
  ],
);

You can notice that StatefulShellRoute acts as a dashboard or home page where your bottom tab selection is defined. Furthermore, it is interesting to note that you can also set the path in initialLocation from the StatefulShellBranch as you can see in the given code snippet above. For me, you can also control where you want to redirect the user based on notifications or user interactions.

Here's the output demo:

gif

Lastly, the source code concept is not originally mine; credit goes to the original source.

I hope it helps!

Upvotes: 0

Related Questions