Skip to main content

flutter-implementing-navigation-and-routing

Handles routing, navigation, and deep linking in a Flutter application. Use when moving between screens or setting up URL-based navigation.

Aller à l'installation

Informations de source

Dépôt
tomevault-io/tomes
Dernière activité de la source
23 juillet 2026 à 21:48
Langue détectée de SKILL.md
anglais
Étoiles
1
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
flutter-implementing-navigation-and-routing
description
Handles routing, navigation, and deep linking in a Flutter application. Use when moving between screens or setting up URL-based navigation.
metadata
{"author":"btwld"}
# Implementing Navigation and Routing in Flutter ## Contents - [Core Concepts](#core-concepts) - [Implementing Imperative Navigation](#implementing-imperative-navigation) - [Implementing Declarative Navigation](#implementing-declarative-navigation) - [Implementing Nested Navigation](#implementing-nested-navigation) - [Workflows](#workflows) - [Examples](#examples) ## Core Concepts - **Routes:** In Flutter, screens and pages are referred to as *routes*. A route is simply a widget. This is equivalent to an `Activity` in Android or a `ViewController` in iOS. - **Navigator vs. Router:** - Use `Navigator` (Imperative) for small applications without complex deep linking requirements. It manages a stack of `Route` objects. - Use `Router` (Declarative) for applications with advanced navigation, web URL synchronization, and specific deep linking requirements. - **Deep Linking:** Allows an app to open directly to a specific location based on a URL. Supported on iOS, Android, and Web. Web requires no additional setup. - **Named Routes:** Avoid using named routes (`MaterialApp.routes` and `Navigator.pushNamed`) for most applications. They have rigid deep linking behavior and do not support the browser forward button. Use a routing package like `go_router` instead. ## Implementing Imperative Navigation Use the `Navigator` widget to push and pop routes using platform-specific transition animations (`MaterialPageRoute` or `CupertinoPageRoute`). ### Pushing and Popping - Navigate to a new route using `Navigator.push(context, route)`. - Return to the previous route using `Navigator.pop(context)`. - Use `Navigator.pushReplacement()` to replace the current route, or `Navigator.pushAndRemoveUntil()` to clear the stack based on a condition. ### Passing and Returning Data - **Sending Data:** Pass data directly into the constructor of the destination widget. Alternatively, pass data via the `settings: RouteSettings(arguments: data)` parameter of the `PageRoute` and extract it using `ModalRoute.of(context)!.settings.arguments`. - **Returning Data:** Pass the return value to the `pop` method: `Navigator.pop(context, resultData)`. Await the result on the pushing side: `final result = await Navigator.push(...)`. ## Implementing Declarative Navigation For apps requiring deep linking, web URL support, or complex routing, implement the `Router` API via a declarative routing package like `go_router`. - Switch from `MaterialApp` to `MaterialApp.router`. - Define a router configuration that parses route paths and configures the `Navigator` automatically. - Navigate using package-specific APIs (e.g., `context.go('/path')`). - **Page-backed vs. Pageless Routes:** Declarative routes are *page-backed* (deep-linkable). Imperative pushes (e.g., dialogs, bottom sheets) are *pageless*. Removing a page-backed route automatically removes all subsequent pageless routes. ## Implementing Nested Navigation Implement nested navigation to manage a sub-flow of screens (e.g., a multi-step setup process or persistent bottom navigation tabs) independently from the top-level global navigator. - Instantiate a new `Navigator` widget inside the host widget. - Assign a `GlobalKey<NavigatorState>` to the nested `Navigator` to control it programmatically. - Implement the `onGenerateRoute` callback within the nested `Navigator` to resolve sub-routes. - Intercept hardware back button presses using `PopScope` to prevent the top-level navigator from popping the entire nested flow prematurely. ## Workflows ### Workflow: Standard Screen Transition Copy this checklist to track progress when implementing a basic screen transition: - [ ] Create the destination widget (Route). - [ ] Define required data parameters in the destination widget's constructor. - [ ] Implement `Navigator.push()` in the source widget. - [ ] Wrap the destination widget in a `MaterialPageRoute` or `CupertinoPageRoute`. - [ ] Implement `Navigator.pop()` in the destination widget to return. ### Workflow: Implementing Deep-Linkable Routing Use this conditional workflow when setting up app-wide routing: - [ ] **If** the app is simple and requires no deep linking: - [ ] Use standard `MaterialApp` and `Navigator.push()`. - [ ] **If** the app requires deep linking, web support, or complex flows: - [ ] Add the `go_router` package. - [ ] Change `MaterialApp` to `MaterialApp.router`. - [ ] Define the `GoRouter` configuration with all top-level routes. - [ ] Replace `Navigator.push()` with `context.go()` or `context.push()`. ### Workflow: Creating a Nested Navigation Flow Run this workflow when building a multi-step sub-flow (e.g., IoT device setup): - [ ] Define string constants for the nested route paths. - [ ] Create a `GlobalKey<NavigatorState>` in the host widget's state. - [ ] Return a `Navigator` widget in the host's `build` method, passing the key. - [ ] Implement `onGenerateRoute` in the nested `Navigator` to map string paths to specific step widgets. - [ ] Wrap the host `Scaffold` in a `PopScope` to handle back-button interceptions (e.g., prompting "Are you sure you want to exit setup?"). - [ ] Use `navigatorKey.currentState!.pushNamed()` to advance steps within the flow. ## Examples ### Example: Passing Data via Constructor (Imperative) ```dart // 1. Define the data model class Todo { final String title; final String description; const Todo(this.title, this.description); } // 2. Source Screen class TodosScreen extends StatelessWidget { final List<Todo> todos; const TodosScreen({super.key, required this.todos}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Todos')), body: ListView.builder( itemCount: todos.length, itemBuilder: (context, index) { return ListTile( title: Text(todos[index].title), onTap: () { // Push and pass data via constructor Navigator.push( context, MaterialPageRoute( builder: (context) => DetailScreen(todo: todos[index]), ), ); }, ); }, ), ); } } // 3. Destination Screen class DetailScreen extends StatelessWidget { final Todo todo; const DetailScreen({super.key, required this.todo}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(todo.title)), body: Padding( padding: const EdgeInsets.all(16), child: Text(todo.description), ), ); } } ``` ### Example: Nested Navigation Flow ```dart class SetupFlow extends StatefulWidget { final String initialRoute; const SetupFlow({super.key, required this.initialRoute}); @override State<SetupFlow> createState() => _SetupFlowState(); } class _SetupFlowState extends State<SetupFlow> { final _navigatorKey = GlobalKey<NavigatorState>(); void _exitSetup() => Navigator.of(context).pop(); @override Widget build(BuildContext context) { return PopScope( canPop: false, onPopInvokedWithResult: (didPop, _) async { if (didPop) return; // Intercept back button to prevent accidental exit _exitSetup(); }, child: Scaffold( appBar: AppBar(title: const Text('Setup')), body: Navigator( key: _navigatorKey, initialRoute: widget.initialRoute, onGenerateRoute: _onGenerateRoute, ), ), ); } Route<Widget> _onGenerateRoute(RouteSettings settings) { Widget page; switch (settings.name) { case 'step1': page = StepOnePage( onComplete: () => _navigatorKey.currentState!.pushNamed('step2'), ); break; case 'step2': page = StepTwoPage(onComplete: _exitSetup); break; default: throw StateError('Unexpected route name: ${settings.name}!'); } return MaterialPageRoute( builder: (context) => page, settings: settings, ); } } ``` --- > Source: [btwld/superdeck](https://github.com/btwld/superdeck) — distributed by [TomeVault](https://tomevault.io). <!-- tomevault:4.0:skill_md:2026-07-01 -->
Voir sur GitHub