Skip to content

Latest commit

 

History

History
289 lines (235 loc) · 9.99 KB

README.md

File metadata and controls

289 lines (235 loc) · 9.99 KB

go_router_flow


This package was created for SportsVisio's apps, and it's currently in use and tested, and it'll be updated until the day go_router implements it.

This is a fork of the go_router package that let's you communicate between pages by returning values on pop like in navigator 1.0. This was implemented by adding completers in the routes and waiting for the values when requested.

Returning values

This is the reason for this package, to be able to return stuff when a screens pop.

Waiting for a value to be returned:

onTap: () {
  // In the new page you can do 'context.pop<bool>(someValue)' to return a value.
  final bool? result = await context.push<bool>('/page2');

  WidgetsBinding.instance.addPostFrameCallback((_) {
    if(result ?? false)...
  });
}

Returning a value:

onTap: () => context.pop(true)

Features

GoRouter has a number of features to make navigation straightforward:

  • Parsing path and query parameters using a template syntax (for example, "user/:id')
  • Displaying multiple screens for a destination (sub-routes)
  • Redirection support - you can re-route the user to a different URL based on application state, for example to a sign-in when the user is not authenticated
  • Support for multiple Navigators via ShellRoute - you can display an inner Navigator that displays its own pages based on the matched route. For example, to display a BottomNavigationBar that stays visible at the bottom of the screen
  • Support for both Material and Cupertino apps
  • Backwards-compatibility with Navigator API

Follow the package install instructions, and you can start using go_router_flow in your app:

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

void main() => runApp(App());

class App extends StatelessWidget {
  App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
      title: 'GoRouter Example',
    );
  }

  final GoRouter _router = GoRouter(
    routes: <GoRoute>[
      GoRoute(
        path: '/',
        builder: (BuildContext context, GoRouterState state) {
          return ScreenA();
        },
      ),
      GoRoute(
        path: '/b',
        builder: (BuildContext context, GoRouterState state) {
          return ScreenB();
        },
      ),
    ],
  );
}

Define Routes

go_router is governed by a set of routes which are specified as part of the GoRouter constructor:

GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const Page1Screen(),
    ),
    GoRoute(
      path: '/page2',
      builder: (context, state) => const Page2Screen(),
    ),
  ],
);

In the above snippet, two routes are defined, / and /page2. When the URL changes, it is matched against each route path. The path is matched in a case-insensitive way, but the case for parameters is preserved. If there are multiple route matches, the first match in the list takes priority over the others.

The builder is responsible for building the Widget to display on screen. Alternatively, you can use pageBuilder to customize the transition animation when that route becomes active. The default transition is used between pages depending on the app at the top of its widget tree, e.g. the use of MaterialApp will cause go_router to use the MaterialPage transitions. Consider using pageBuilder for custom Page class.

Initialization

Create a GoRouter object and initialize your MaterialApp or CupertinoApp:

final GoRouter _router = GoRouter(
  routes: <GoRoute>[
     // ...
  ]
);

MaterialApp.router(
  routerConfig: _router,
);

Error handling

By default, go_router comes with default error screens for both MaterialApp and CupertinoApp as well as a default error screen in the case that none is used. Once can also replace the default error screen by using the errorBuilder:

GoRouter(
  ...
  errorBuilder: (context, state) => ErrorScreen(state.error),
);

Redirection

You can use redirection to prevent the user from visiting a specific page. In go_router, redirection can be asynchronous.

GoRouter(
  ...
  redirect: (context, state) async {
    if (await LoginService.of(context).isLoggedIn) {
      return state.location;
    }
    return '/login';
  },
);

If the code depends on BuildContext through the dependOnInheritedWidgetOfExactType (which is how of methods are usually implemented), the redirect will be called every time the InheritedWidget updated.

Top-level redirect

The GoRouter.redirect is always called for every navigation regardless of which GoRoute was matched. The top-level redirect always takes priority over route-level redirect.

Route-level redirect

If the top-level redirect does not redirect to a different location, the GoRoute.redirect is then called if the route has matched the GoRoute. If there are multiple GoRoute matches, e.g. GoRoute with sub-routes, the parent route redirect takes priority over sub-routes' redirect.

Navigation

To navigate between routes, use the GoRouter.go method:

onTap: () => GoRouter.of(context).go('/page2')

go_router also provides a more concise way to navigate using Dart extension methods:

onTap: () => context.go('/page2')

Nested Navigation

The ShellRoute route type provides a way to wrap all sub-routes with a UI shell. Under the hood, GoRouter places a Navigator in the widget tree, which is used to display matching sub-routes:

final  _router = GoRouter(
  routes: [
    ShellRoute(
      builder: (context, state, child) {
        return AppScaffold(child: child);
      },
      routes: <RouteBase>[
        GoRoute(
          path: '/albums',
          builder: (context, state) {
            return HomeScreen();
          },
          routes: <RouteBase>[
            /// The details screen to display stacked on the inner Navigator.
            GoRoute(
              path: 'song/:songId',
              builder: (BuildContext context, GoRouterState state) {
                return const DetailsScreen(label: 'A');
              },
            ),
          ],
        ),
      ],
    ),
  ],
);

For more details, see the ShellRoute API documentation. For a complete example, see the ShellRoute sample in the example/ directory.

Still not sure how to proceed?

See examples for complete runnable examples or visit API documentation

Migration guides

Changelog

See the Changelog for a list of new features and breaking changes.

Maintainer

Collaborators