From e396cc79eab81157e82110579254241e4d71f6d3 Mon Sep 17 00:00:00 2001 From: matthew-carroll Date: Mon, 4 Jun 2018 17:20:04 -0700 Subject: [PATCH] Documented embedded navigators in the Navigator class file (#15040). (#18051) * Documented nested navigators in the Navigator class file (#15040). --- .../flutter/lib/src/widgets/navigator.dart | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index f440a733d2..f3d6ee4b54 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -551,6 +551,100 @@ class NavigatorObserver { /// because it doesn't depend on its animation parameters (elided with `_` /// and `__` in this example). The transition is built on every frame /// for its duration. +/// +/// ### Nesting Navigators +/// +/// An app can use more than one Navigator. Nesting one Navigator below +/// another Navigator can be used to create an "inner journey" such as tabbed +/// navigation, user registration, store checkout, or other independent journeys +/// that represent a subsection of your overall application. +/// +/// #### Real World Example +/// +/// It is standard practice for iOS apps to use tabbed navigation where each +/// tab maintains its own navigation history. Therefore, each tab has its own +/// [Navigator], creating a kind of "parallel navigation." +/// +/// In addition to the parallel navigation of the tabs, it is still possible to +/// launch full-screen pages that completely cover the tabs. For example: an +/// on-boarding flow, or an alert dialog. Therefore, there must exist a "root" +/// [Navigator] that sits above the tab navigation. As a result, each of the +/// tab's [Navigator]s are actually nested [Navigator]s sitting below a single +/// root [Navigator]. +/// +/// The nested [Navigator]s for tabbed navigation sit in [WidgetApp] and +/// [CupertinoTabView], so you don't need to worry about nested [Navigator]s +/// in this situation, but it's a real world example where nested [Navigator]s +/// are used. +/// +/// #### Sample Code +/// +/// The following example demonstrates how a nested [Navigator] can be used to +/// present a standalone user registration journey. +/// +/// Even though this example uses two [Navigator]s to demonstrate nested +/// [Navigator]s, a similar result is possible using only a single [Navigator]. +/// +/// ```dart +/// class MyApp extends StatelessWidget { +/// @override +/// Widget build(BuildContext context) { +/// return new MaterialApp( +/// // ...some parameters omitted... +/// // MaterialApp contains our top-level Navigator +/// initialRoute: '/', +/// routes: { +/// '/': (BuildContext context) => new HomePage(), +/// '/signup': (BuildContext context) => new SignUpPage(), +/// }, +/// ); +/// } +/// } +/// +/// class SignUpPage extends StatelessWidget { +/// @override +/// Widget build(BuildContext context) { +/// // SignUpPage builds its own Navigator which ends up being a nested +/// // Navigator in our app. +/// return new Navigator( +/// initialRoute: 'signup/personal_info', +/// onGenerateRoute: (RouteSettings settings) { +/// WidgetBuilder builder; +/// switch (settings.name) { +/// case 'signup/personal_info': +/// // Assume CollectPersonalInfoPage collects personal info and then +/// // navigates to 'signup/choose_credentials'. +/// builder = (BuildContext _) => new CollectPersonalInfoPage(); +/// break; +/// case 'signup/choose_credentials': +/// // Assume ChooseCredentialsPage collects new credentials and then +/// // invokes 'onSignupComplete()'. +/// builder = (BuildContext _) => new ChooseCredentialsPage( +/// onSignupComplete: () { +/// // Referencing Navigator.of(context) from here refers to the +/// // top level Navigator because SignUpPage is above the +/// // nested Navigator that it created. Therefore, this pop() +/// // will pop the entire "sign up" journey and return to the +/// // "/" route, AKA HomePage. +/// Navigator.of(context).pop(); +/// }, +/// ); +/// break; +/// default: +/// throw new Exception('Invalid route: ${settings.name}'); +/// } +/// return new MaterialPageRoute(builder: builder, settings: settings); +/// }, +/// ); +/// } +/// } +/// ``` +/// +/// [Navigator.of] operates on the nearest ancestor [Navigator] from the given +/// [BuildContext]. Be sure to provide a [BuildContext] below the intended +/// [Navigator], especially in large [build] methods where nested [Navigator]s +/// are created. The [Builder] widget can be used to access a [BuildContext] at +/// a desired location in the widget subtree. class Navigator extends StatefulWidget { /// Creates a widget that maintains a stack-based history of child widgets. ///