1
0
mirror of https://github.com/flutter/samples.git synced 2025-11-08 13:58:47 +00:00
Files
samples/navigation_and_routing
Brett Morgan 5401bb88b4 Flutter 3.7.0 (#1556)
* Update `simplistic_editor` for Flutter 3.4 beta

* Re-enable beta and master CI

* Disable on master

* Added sample code for using plugins and channels from background isolates.

* goderbauer feedback 1

* goderbauer feedback2

* goderbauer feedback 3

* Add `background_isolate_channels` to CI

* Enable beta CI

* Enable all `stable` CI projects

* `dart fix --apply`

* `print` -> `denugPrint`

* Make deps min version not pinned

* Drop `_isDebug`

* Remove unused import

* `dart format`

* Fixup `linting_tool`

* Fixup `form_app`

* Enable all `master` CI

* Basic fixes

* Patch `simplistic_editor`

* Fix nl at eol

* Comment out `simplistic_editor`

* Incorporating @bleroux's latest changes

* Clean up CI scripts

* Copy `experimental/material_3_demo` to top level

* Update `game_template`

* Update `animations`

* Update `desktop_photo_search`

* Update `flutter_maps_firestore`

* Update `form_app`

* Update `infinite_list`

* Update `isolate_example`

* Update `jsonexample`

* Update `navigation_and_routing`

* Update `place_tracker`

* Update `platform_channels`

* Update `platform_design`

* Update `provider_shopper`

* Fixup `context_menus`

* `dart format`

* Update the main `material_3_demo`

* Make `tool/flutter_ci_script_stable.sh` executable again

Co-authored-by: Bruno Leroux <bruno.leroux@gmail.com>
Co-authored-by: Aaron Clarke <aaclarke@google.com>
2023-01-25 09:08:51 +10:00
..
2023-01-25 09:08:51 +10:00
2023-01-25 09:08:51 +10:00
2023-01-25 09:08:51 +10:00
2023-01-25 09:08:51 +10:00
2023-01-25 09:08:51 +10:00
2023-01-25 09:08:51 +10:00
2023-01-25 09:08:51 +10:00
2022-05-11 12:48:11 -07:00

Navigation and Routing

A sample that shows how to use the Router API to handle common navigation scenarios.

Goals

  • Demonstrate common navigation scenarios:
    • Parsing path parameters ('/user/:id')
    • Sign in (validation / guards)
    • Nested navigation
  • Provide a reusable implementation of RouterDelegate and RouteInformationParser
  • Demonstrate how deep linking is configured on iOS and Android
  • Demonstrate how to use the Link widget from package:url_Launcher with the Router API.

How it works

The top-level widget, Bookstore, sets up the state for this app. It places three InheritedNotifier widgets in the tree: RouteStateScope, BookstoreAuthScope, and LibraryScope, which provide the state for the application:

  • RouteState: stores the current route path (/book/1) as a ParsedRoute object (see below).
  • BookstoreAuthScope: stores a mock authentication API, BookstoreAuth.
  • LibraryScope: stores the data for the app, Library.

The Bookstore widget also uses the MaterialApp.router() constructor to opt-in to the Router API. This constructor requires a RouterDelegate and RouteInformationParser. This app uses the routing.dart library, described below.

routing.dart

This library contains a general-purpose routing solution for medium-sized apps. It implements these classes:

  • SimpleRouterDelegate: Implements RouterDelegate. Updates RouteState when a new route has been pushed to the application by the operating system. Also notifies the Router widget whenever the RouteState changes.
  • TemplateRouteParser: Implements RouteInformationParser. Parses the incoming route path into a ParsedRoute object. A RouteGuard can be provided to guard access to certain routes.
  • ParsedRoute: Contains the current route location ("/user/2"), path parameters ({id: 2}), query parameters ("?search=abc"), and path template ("/user/:id")
  • RouteState: Stores the current ParsedRoute.
  • RouteGuard: Guards access to routes. Can be overridden to redirect the incoming route if a condition isn't met.

App Structure

The SimpleRouterDelegate constructor requires a WidgetBuilder parameter and a navigatorKey. This app uses a BookstoreNavigator widget, which configures a Navigator with a list of pages, based on the current RouteState.

SimpleRouterDelegate(
  routeState: routeState,
  navigatorKey: navigatorKey,
  builder: (context) => BookstoreNavigator(
    navigatorKey: navigatorKey,
  ),
);

This Navigator is configured to display either the sign-in screen or the BookstoreScaffold. An additional screen is stacked on top of the BookstoreScaffold if a book or author is currently selected:

return Navigator(
  key: widget.navigatorKey,
  onPopPage: (route, dynamic result) {
    // ...
  },
  pages: [
    if (routeState.route.pathTemplate == '/signin')
      FadeTransitionPage<void>(
        key: signInKey,
        child: SignInScreen(),
      ),
    else ...[
      FadeTransitionPage<void>(
        key: scaffoldKey,
        child: BookstoreScaffold(),
      ),
      if (selectedBook != null)
        MaterialPage<void>(
          key: bookDetailsKey,
          child: BookDetailsScreen(
            book: selectedBook,
          ),
        )
      else if (selectedAuthor != null)
        MaterialPage<void>(
          key: authorDetailsKey,
          child: AuthorDetailsScreen(
            author: selectedAuthor,
          ),
        ),
    ],
  ],
);

The BookstoreScaffold widget uses package:adaptive_navigation to build a navigation rail or bottom navigation bar based on the size of the screen. The body of this screen is BookstoreScaffoldBody, which configures a nested Navigator to display either the AuthorsScreen, SettingsScreen, or BooksScreen widget.

Linking vs updating RouteState

There are two ways to change the current route, either by updating RouteState, which the RouterDelegate listens to, or use the Link widget from package:url_launcher. The SettingsScreen widget demonstrates both options:

Link(
  uri: Uri.parse('/book/0'),
  builder: (context, followLink) {
    return TextButton(
      child: const Text('Go directly to /book/0 (Link)'),
      onPressed: followLink,
    );
  },
),
TextButton(
  child: const Text('Go directly to /book/0 (RouteState)'),
  onPressed: () {
    RouteStateScope.of(context)!.go('/book/0');
  },
),

Questions/issues

If you have a general question about the Router API, the best places to go are:

If you run into an issue with the sample itself, please file an issue in the main Flutter repo.