reading
Based on the Navigator1.0:
- Annotations for Flutter routing
- Annotated route 2.0 by Flutter method
- Annotated route 4.0 by the Flutter method
preface
With the release of Flutter 1.22 comes Navigator2.0, which gives developers more options. You can flexibly manage the routing stack, handle typing in the browser, and nest multiple Navigators. There are still disadvantages to Flutter 1.22, but you can basically route yourself. Follow me into the world of Flutter routing. The source version of this article is Flutter Stable 1.22.6.
Routing based
Navigator
It is responsible for the entire routing Stack, which is actually an Overlay on the structure, which is kind of like a Stack, and people often use it to make toast, like an oktoast, where each page is actually an OverlayEntry.
RouteSettings
Saves the route name and parameters
Page
Navigator2.0, inherited from RouteSettings. I am responsible for creating the Route and carrying a key, which is the basis for the subsequent Page changes. Note that this key should normally be a unique key.
Route
Animating the jumps and saving the RouteSettings (route names and parameters). Also the link between OverlayEntry, Navigator, _RouteEntry.
- in
push
Method,Route
Pass it in, assign it to_RouteEntry
Increased to_history
中
Future<T> push<T extends Object>(Route<T> route) {
_history.add(_RouteEntry(route, initialState: _RouteLifecycle.push));
_flushHistoryUpdates();
_afterNavigation(route);
return route.popped;
}
Copy the code
NavigatorState.build
The value of initialEntries for Overlay in _history is equal to the OverlayEntry of all _routeentry. route in _history
可迭代<OverlayEntry> get _allRouteOverlayEntries sync* {
for (final _RouteEntry entry in _history)
yield* entry.route.overlayEntries;
}
Overlay(
key: _overlayKey,
initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const <OverlayEntry>[],
),
Copy the code
RouteTransitionRecord / _RouteEntry
The latter inherits the former and records the status of each route
RouteTransitionRecord has the following properties and methods, they are TransitionDelegate. Set in the resolve method
IsWaitingForEnteringDecision routing is waiting to enter the screen isWaitingForExitingDecision marking routing is waiting to leave the screen
methods | In and out | animation | Returns the parameter |
---|---|---|---|
markForPush() | Into the | There are | N/A |
markForAdd() | Into the | There is no | N/A |
markForPop([dynamic result]) | Out of the | There are | There are |
markForComplete([dynamic result]) | Out of the | There is no | There are |
markForRemove() | Out of the | There is no | There is no |
TransitionDelegate / DefaultTransitionDelegate
Set in the RouteTransitionRecord in TransitionDelegate. Resolve.
1. When the Pages change triggered update, perform the NavigatorState. DidUpdateWidget 2. In this method, the old Pages and the new Pages are compared. 3. Resolve determines which Pages are added and which are removed.
DefaultTransitionDelegate about logic in the below
New Pages | The old Pages | state |
---|---|---|
A=>B | A=>B=>C | C markForPop |
A=>C | A=>B=>C | B markForComplete |
A=>B=>C=>D | A=>B=>C | D markForPush |
A=>B=>D=>C | A=>B=>C | D markForAdd |
NavigatorObserver
Monitor push, POP, replace, remove routes, and swipe left to exit on ios. This is usually where we can make page entry and exit burials, as well as resolve conflicts between the Flutter and native ios swipe left exit in mixed development.
class NavigatorObserver {
NavigatorState get navigator => _navigator;
NavigatorState _navigator;
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { }
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { }
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) { }
void didReplace({ Route<dynamic> newRoute, Route<dynamic> oldRoute }) { }
void didStartUserGesture(Route<dynamic> route, Route<dynamic> previousRoute) { }
void didStopUserGesture() { }
}
Copy the code
The Navigator 1.0
It is recommended to use named routes and manage routes uniformly in the onGenerateRoute callback. The French routing annotations are also based on Navigator 1.0.
- Annotations for Flutter routing
- Annotated route 2.0 by Flutter method
- Annotated route 4.0 by the Flutter method
The Navigator 2.0
Let’s take a look at some of the changes in the Navigator’s latest build.
const Navigator({
Key key,
// New in Navigator 2.0, which indirectly exposes the routing stack to users
this.pages = const <Page<dynamic> > [].// A callback when using code pop or pressing the browser back button, at which point the user can handle the logic themselves
this.onPopPage,
this.initialRoute,
this.onGenerateInitialRoutes = Navigator.defaultGenerateInitialRoutes,
this.onGenerateRoute,
this.onUnknownRoute,
Since Pages is exposed to the user, you can set the page's TransitionDelegate state yourself, as shown in the [TransitionDelegate] section above. In general, just use the default
this.transitionDelegate = const DefaultTransitionDelegate<dynamic> (),// Whether to notify the engine, mainly on the Web, of URL changes to the browser, synchronization address
this.reportsRouteUpdateToEngine = false.this.observers = const <NavigatorObserver>[],
})
Copy the code
The Navigator chestnuts
- Let’s get ready
Page
, simple implementationcreateRoute
methods
class MyPage extends Page<void> {
const MyPage({
@required LocalKey key,
@required String name,
@required this.widget,
Object arguments,
}) : super(
key: key,
name: name,
arguments: arguments,
);
final Widget widget;
@override
Route<void> createRoute(BuildContext context) {
return MaterialPageRoute<void>(
settings: this, builder: (BuildContext context) => widget, ); }}Copy the code
- To prepare
pages
This is our routing stack, initializing a MainPage. Note that the key must be a unique key.
final List<MyPage> _pages = <MyPage>[
MyPage(
name: 'MainPage', widget: const TestPage('MainPage'), key: UniqueKey()),
];
Copy the code
- With Navigator, it’s worth noting
pages
It should be a new set, like thisNavigatorState.didUpdateWidget
Will judge the difference, and updateonPopPage
Callbacks can operate on their own, and then finallysetState
To informpages
Change. By calling thenavigatorKey.currentState.pop()
Either clicking the Appbar back button triggers the callback
Navigator(
reportsRouteUpdateToEngine: true,
key: navigatorKey,
pages: _pages.toList(),
onPopPage: (Route<dynamic> route, dynamic result) {
if (_pages.length > 1) {
_pages.removeLast();
setState(() {});
return route.didPop(result);
}
return false; },),Copy the code
- Now you can manipulate the routing stack in any way you want. Here are a few examples.
Add a new page, equivalent to a push
_pages.add(
MyPage(
name: 'MainPageA',
widget: const TestPage('MainPageA'),
key: UniqueKey()),
);
setState(() {});
Copy the code
Remove the last one, equivalent to pop
if (_pages.length > 1) {
_pages.removeLast();
setState(() {});
}
Copy the code
Trigger the onPopPage callback directly using the Navigatorstate.pop () method
navigatorKey.currentState.pop();
Copy the code
- Full Demo address
Now that it looks like we can control the entire routing stack perfectly, isn’t that enough? The answer is definitely not enough, and we haven’t dealt with browser input to modify urls, browser back keys, Android physical back keys, and Navigator nesting.
Router
What’s new in Navigator 2.0 is, at first glance, all new.
const Router({
Key key,
this.routeInformationProvider,
this.routeInformationParser,
@required this.routerDelegate,
this.backButtonDispatcher,
})
Copy the code
RouteInformation
There are two scenarios:
- RouteInformationProvider => Router, which occurs when a new route is available, such as entering a new URL in the browser or initializing the route in code Settings.
- The Router = > RouteInformationProvider, that only happens in the notification engine change the browser URL.
class RouteInformation {
const RouteInformation({this.location, this.state});
/// Such as:` / `.`/path`.`/path/to/the/app`.
final String location;
/// The current page state, such as scroll position, must be serializable.
final Object state;
}
Copy the code
RouteInformationParser
I was responsible for parsing RouteInformation, where T was usually String or RouteSettings, which was convenient for us to resolve.
abstract class RouteInformationParser<T> {
const RouteInformationParser();
/// Enter a new URL in the browser or initialize the route in the code Settings
Future<T> parseRouteInformation(RouteInformation routeInformation);
/// Note if reportsRouteUpdateToEngine set to true, this must be implemented, can not return null.
/// T from the incoming RouterDelegate currentConfiguration gain
RouteInformation restoreRouteInformation(T configuration) => null;
}
Copy the code
RouteInformationProvider
Mainly responsible for notifying RouteInformation changes
abstract class RouteInformationProvider extends ValueListenable<RouteInformation> {
void routerReportsNewRouteInformation(RouteInformation routeInformation) {}
}
Copy the code
It is often used to initialize routes
routeInformationProvider: PlatformRouteInformationProvider(
initialRouteInformation: const RouteInformation(
location: '/mainpage',),),Copy the code
RouterDelegate
Create and configure the proxy for the Navigator, much like the Navigator demo you wrote earlier. The difference is added to the browser input to modify the URL, browser back key, Android physical back key processing.
abstract class RouterDelegate<T> extends Listenable {
/// Initializing the route calls this method
Future<void> setInitialRoutePath(T configuration) {
return setNewRoutePath(configuration);
}
/// Add routes such as entering a new URL in the browser or initializing routes in code Settings
Future<void> setNewRoutePath(T configuration);
/// 'Browser back key'.'Android physics back key'The method is called
Future<bool> popRoute();
/// RouteInformationParser restoreRouteInformation will
/// Get this value for reporting to the engine, especially in Web applications
T get currentConfiguration => null;
/// Returns the Navigator
Widget build(BuildContext context);
}
Copy the code
PopNavigatorRouterDelegateMixin
Implements popRoute methods in RouterDelegate, not required.
mixin PopNavigatorRouterDelegateMixin<T> on RouterDelegate<T> {
/// The key used for retrieving the current navigator.
///
/// When using this mixin, be sure to use this key to create the navigator.
GlobalKey<NavigatorState> get navigatorKey;
@override
Future<bool> popRoute() {
finalNavigatorState navigator = navigatorKey? .currentState;if (navigator == null)
return SynchronousFuture<bool> (false);
returnnavigator.maybePop(); }}Copy the code
Source code analysis
I’ve just said which APIS solve which problems, but let’s track how the official implementation works. I’ll type in a new URL in the browser.
-
From the last step on the diagram, it is clear that this is a native approach from the engine
-
By _handleNavigationInvocation method, pop and push here, here is the receiving to notification of the engine including browser input, the browser and the android back button click physics.
Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) {
switch (methodCall.method) {
case 'popRoute':
return handlePopRoute();
case 'pushRoute':
return handlePushRoute(methodCall.arguments as String);
case 'pushRouteInformation':
return _handlePushRouteInformation(methodCall.arguments as Map<dynamic.dynamic>);
}
return Future<dynamic>.value();
}
Copy the code
- In the method, give the registered ones
WidgetsBindingObserver
Distribute the event, and return when it is found and processed. (Embedded nesting hereNavigator
The pit of)
Future<void> handlePushRoute(String route) async {
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) {
if (await observer.didPushRoute(route))
return;
}
}
Future<void> handlePopRoute() async {
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) {
if (await observer.didPopRoute())
return;
}
SystemNavigator.pop();
}
Future<void> _handlePushRouteInformation(Map<dynamic.dynamic> routeArguments) async {
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.from(_observers)) {
if (
await observer.didPushRouteInformation(
RouteInformation(
location: routeArguments['location'] as String,
state: routeArguments['state'] as Object))),return; }}Copy the code
- WidgetsApp inherits WidgetsBindingObserver in
WidgetsBinding.instance.addObserver(this)
Add yourself to the list_observers
inside
class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
}
@override
Future<bool> didPushRoute(String route) async{}Copy the code
- while
PlatformRouteInformationProvider
Add itself to addListener during Router initialization_observers
In the.
class _RouterState<T> extends State<Router<T>> {
@override
void initState() {
super.initState(); widget.routeInformationProvider? .addListener(_handleRouteInformationProviderNotification);Copy the code
class PlatformRouteInformationProvider extends RouteInformationProvider with WidgetsBindingObserver.ChangeNotifier {
@override
void addListener(VoidCallback listener) {
if(! hasListeners) WidgetsBinding.instance.addObserver(this);
super.addListener(listener);
}
Copy the code
Finally, we can get the route changes that the engine tells us!
BackButtonDispatcher
includingRootBackButtonDispatcher
和 ChildBackButtonDispatcher
. Mainly for the purpose of solvingThe Navigator nested
To return to the button priority question.
Here’s an example:
1.MyApp is a Navigator. The initial page is NestedMainPage. Now the first two pages in the Navigator (NestedMainPage ChildRouterPage)
2.ChildRouterPage is also a Navigator. The initial page is NestedTestPage. There are now two pages in the first Navigator (NestedTestPage,TestPageA)
3. Now we can see TestPageA, so what happens when you press the Android physical back button or the Browser Back button?
4. The page returns to the NestedMainPage, which must not be the desired result?
So how do we solve this problem? We know that we have a way to monitor in front Android physical return key Browser or the return key, namely _handleNavigationInvocation popRoute callback in the method, But the first popable Navigator (remember the pit when it was distributed) was processed first. We can actually decide for ourselves which Navigator the popRoute callback applies to. We just need to do the following on the second Router.
Get the backButtonDispatcher from the previous Router and get the priority.
Widget build(BuildContext context) {
final ChildBackButtonDispatcher childBackButtonDispatcher =
Router.of(context)
.backButtonDispatcher
.createChildBackButtonDispatcher();
childBackButtonDispatcher.takePriority();
return Router<RouteSettings>(
backButtonDispatcher: childBackButtonDispatcher,
);
}
Copy the code
Source code analysis:
- Something very familiar
WidgetsBindingObserver
.addCallback
Add yourself to the monitor_observers
, wait for the engine to deliver the event,WidgetsBinding
In the distribution.
class RootBackButtonDispatcher extends BackButtonDispatcher with WidgetsBindingObserver {
RootBackButtonDispatcher();
@override
void addCallback(ValueGetter<Future<bool>> callback) {
if(! hasCallbacks) WidgetsBinding.instance.addObserver(this);
super.addCallback(callback);
}
@override
void removeCallback(ValueGetter<Future<bool>> callback) {
super.removeCallback(callback);
if(! hasCallbacks) WidgetsBinding.instance.removeObserver(this);
}
@override
Future<bool> didPopRoute() => invokeCallback(Future<bool>.value(false));
}
Copy the code
- In the call
takePriority
Method when talking about yourself add toparent
的children
Make sure you’re the last one and have emptied yourschildren
.
class ChildBackButtonDispatcher extends BackButtonDispatcher {
ChildBackButtonDispatcher(this.parent) : assert(parent ! =null);
final BackButtonDispatcher parent;
@protected
Future<bool> notifiedByParent(Future<bool> defaultValue) {
return invokeCallback(defaultValue);
}
@override
void takePriority() {
parent.deferTo(this);
super.takePriority();
}
/// BackButtonDispatcher implementation, easy to explain
void deferTo(ChildBackButtonDispatcher child) {
assert(hasCallbacks); _children ?? = <ChildBackButtonDispatcher>{}as LinkedHashSet<ChildBackButtonDispatcher>;
_children.remove(child); // child may or may not be in the set already
_children.add(child);
}
/// BackButtonDispatcher implementation, easy to explain
void takePriority() {
if(_children ! =null) _children.clear(); }}Copy the code
- in
invokeCallback
Methods,children
The last one starts traversal (that’s why indeferTo
Methods first,remove
After,add
), depending on who handles itdidPopRoute
Event, stop if handled.
Future<bool> invokeCallback(Future<bool> defaultValue) {
if(_children ! =null && _children.isNotEmpty) {
final List<ChildBackButtonDispatcher> children = _children.toList();
int childIndex = children.length - 1;
Future<bool> notifyNextChild(bool result) {
// If the previous child handles the callback, we returns the result.
if (result)
return SynchronousFuture<bool>(result);
// If the previous child did not handle the callback, we ask the next
// child to handle the it.
if (childIndex > 0) {
childIndex -= 1;
return children[childIndex]
.notifiedByParent(defaultValue)
.then<bool>(notifyNextChild);
}
// If none of the child handles the callback, the parent will then handle it.
return super.invokeCallback(defaultValue);
}
return children[childIndex]
.notifiedByParent(defaultValue)
.then<bool>(notifyNextChild);
}
return super.invokeCallback(defaultValue);
}
Copy the code
-
Because there is a listener for BackButtonDispatcher added to the Router (location in the source code), routerDelegate.popRoute will eventually be notified.
-
Full Demo address
The Navigator 2.0 summarizes
- Based on the
Navigator.pages
To achieve complete control of the routing stack. - through
Router
And relatedApi
To solveBrowser input modifies the URL
.Browser back key
.Android Physics back key
Issues with native interaction, and rightNavigator
Proxy and configuration. - through
BackButtonDispatcher
Deal with theThe Navigator nested
The problem.
Navigator 2.0 looks perfect, but there are some downsides.
- It’s a bit much to achieve, isn’t it
duang
Can it be used immediately? - Manual input parameter parsing problem in Web browser
- Due to the
Route
在Page
的createRoute
Method, which we cannot access directlyRoute
. If we were to write something like thispush
What about methods with callback arguments?
Future<T> push<T extends Object>(Route<T> route) {
_history.add(_RouteEntry(route, initialState: _RouteLifecycle.push));
_flushHistoryUpdates();
_afterNavigation(route);
return route.popped;
}
Copy the code
Well, yes, French routing Annotation 5.0 already supports Navigator 1.0 and 2.0 perfectly, scatters!
French routing note 5.0
Increase the reference
Add the reference to Dependencies and the project/packages you need to annotate to pubspec.yaml
dev_dependencies:
ff_annotation_route_core: any
ff_annotation_route_library: any
Copy the code
Execute the flutter Packages get download
Add annotations
Void structure
import 'package:ff_annotation_route/ff_annotation_route.dart';
@FFRoute(
name: "fluttercandies://mainpage",
routeName: "MainPage".)class MainPage extends StatelessWidget
{
// ...
}
Copy the code
Parametric structure
The tool handles constructs with parameters automatically, no special processing is required. The only thing to note is that you need to use argumentImports to provide import addresses for class/enum arguments. Now you can use @ffArgumentimPort () instead
@FFArgumentImport('hide TestMode2')
import 'package:example1/src/model/test_model.dart';
@FFArgumentImport(a)import 'package:example1/src/model/test_model1.dart' hide TestMode3;
import 'package:ff_annotation_route_library/ff_annotation_route_library.dart';
@FFRoute(
name: 'flutterCandies://testPageE',
routeName: 'testPageE',
description: 'Show how to push new page with arguments(class)'.// argumentImports are left in case @ffArgumentimPort () cannot be fully expressed.
// argumentImports: <String>[
// 'import \'package:example1/src/model/test_model.dart\'; ',
// 'import \'package:example1/src/model/test_model1.dart\'; ',
/ /,
exts: <String.dynamic> {'group': 'Complex'.'order': 1,},)class TestPageE extends StatelessWidget {
const TestPageE({
this.testMode = const TestMode(
id: 2,
isTest: false,),this.testMode1,
});
factory TestPageE.deafult() => TestPageE(
testMode: TestMode.deafult(),
);
factory TestPageE.required({@required TestMode testMode}) => TestPageE(
testMode: testMode,
);
final TestMode testMode;
final TestMode1 testMode1;
}
Copy the code
FFRoute
Parameter | Description | Default |
---|---|---|
name | Route name (e.g., “/ Settings “) | required |
showStatusBar | Whether to display the status bar | true |
routeName | The name of the page used for burying data | ‘ ‘ |
pageRouteType | Material, Cupertino, transparent route Type | – |
description | Description of routes | ‘ ‘ |
exts | Other extended parameters. | – |
argumentImports | Import of certain parameters. Some arguments are classes or enumerations, and you need to specify their import address. You can now use @ffArgumentimPort () instead | – |
Generate the file
The environment
Add dart’s bin PATH to your system $PATH.
cache\dart-sdk\bin
For more information
If not, look at the Nuggets
The activation
pub global activate ff_annotation_route
Execute the command
Go to your project root directory and execute it.
ff_route <command> [arguments]
The command parameter
Available commands:
-h, --[no-]help Indicates the help information. -p, --path Command directory. The default directory is the current one. -o, --output route Output path of the helper files relative to the lib folder of the main project. -n, --name Specifies the name of the routing constant class. The default value is`Routes`. -g, --git scans git references for packages. You need to specify the name of the package`, `separate--routes-file-output routes Specifies the path to the output directory of the file. Path relative to main project lib folder --const-ignore ignores some const(not all const are expected to be generated) with regular expressions --[no-] Route-constants Whether 'xxx_route.dart' is in the root project Generate static constants for all routes --[no-]package Whether this is a package --[no-] clades-arguments Whether to generate route parameter help classes-s, --[no-]save Specifies whether to save the command locally. If you save it, you just need to execute it next time`ff_route`That's it.Copy the code
Note the Navigator 1.0
The complete code is in Example
Main.dart
import 'package:ff_annotation_route_library/ff_annotation_route_library.dart';
import 'package:flutter/material.dart';
import 'example_route.dart';
import 'example_routes.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ff_annotation_route demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: Routes.fluttercandiesMainpage,
onGenerateRoute: (RouteSettings settings) {
return onGenerateRoute(
settings: settings,
getRouteSettings: getRouteSettings,
routeSettingsWrapper: (FFRouteSettings ffRouteSettings) {
if (ffRouteSettings.name == Routes.fluttercandiesMainpage ||
ffRouteSettings.name ==
Routes.fluttercandiesDemogrouppage.name) {
return ffRouteSettings;
}
returnffRouteSettings.copyWith( widget: CommonWidget( child: ffRouteSettings.widget, title: ffRouteSettings.routeName, )); }); }); }}Copy the code
Push
Push name
Navigator.pushNamed(context, Routes.fluttercandiesMainpage /* fluttercandies://mainpage */);
Copy the code
Push name with arguments
- The parameter must be one
Map<String, dynamic>
Navigator.pushNamed(
context,
Routes.flutterCandiesTestPageE,
arguments: <String.dynamic>{
constructorName: 'required'.'testMode': const TestMode(
id: 100,
isTest: true,)});Copy the code
- Open – supper – the arguments
Navigator.pushNamed(
context,
Routes.flutterCandiesTestPageE.name,
arguments: Routes.flutterCandiesTestPageE.requiredC(
testMode: const TestMode(
id: 100,
isTest: true,),),);Copy the code
Note the Navigator 2.0
The complete code is in example1
Main.dart
import 'dart:convert';
import 'package:example1/src/model/test_model.dart';
import 'package:ff_annotation_route_library/ff_annotation_route_library.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'example1_route.dart';
import 'example1_routes.dart';
void main() {
// The tool will handle simple types, but not all
// For example, enter the following address in a browser
// http://localhost:64916/#flutterCandies://testPageF? List = (4 and 6) & map = {" DDD ": 123} & testMode = {" id" : 2, "isTest" : true}
// queryParameters will convert to your own type based on your situation
FFConvert.convert = <T>(dynamic value) {
if (value == null) {
return null;
}
print(T);
final dynamic output = json.decode(value.toString());
if (<int> []is T && output is List<dynamic>) {
return output.map<int> ((dynamic e) => asT<int>(e)).toList() as T;
} else if (<String.String> {}is T && output is Map<dynamic.dynamic>) {
return output.map<String.String> ((dynamic key, dynamic value) =>
MapEntry<String.String>(key.toString(), value.toString())) as T;
} else if (const TestMode() is T && output is Map<dynamic.dynamic>) {
return TestMode.fromJson(output) as T;
}
return json.decode(value.toString()) as T;
};
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final FFRouteInformationParser _ffRouteInformationParser =
FFRouteInformationParser();
final FFRouterDelegate _ffRouterDelegate = FFRouterDelegate(
getRouteSettings: getRouteSettings,
pageWrapper: <T>(FFPage<T> ffPage) {
returnffPage.copyWith( widget: ffPage.name == Routes.fluttercandiesMainpage || ffPage.name == Routes.fluttercandiesDemogrouppage.name ? ffPage.widget : CommonWidget( child: ffPage.widget, routeName: ffPage.routeName, ), ); });// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'ff_annotation_route demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
// Initialize the first page
routeInformationProvider: PlatformRouteInformationProvider(
initialRouteInformation: constRouteInformation( location: Routes.fluttercandiesMainpage, ), ), routeInformationParser: _ffRouteInformationParser, routerDelegate: _ffRouterDelegate, ); }}Copy the code
FFRouteInformationParser
Primarily used on the Web, routing tings are translated into RouteSettings when you type them into the browser, or RouteSettings when fed back to the browser
Here’s an example:
xxx? a=1&b=2 <=> RouteSettings(name:’xxx’,arguments:
{‘a’:’1′,’b’:’2′})
FFRouterDelegate
Delegate for creating and configuring navigation, which provides similar methods in Navigator.
FFRouterDelegate.of(context).pushNamed<void>(
Routes.flutterCandiesTestPageF.name,
arguments: Routes.flutterCandiesTestPageF.d(
<int> [1.2.3],
map: <String.String> {'ddd': 'dddd'},
testMode: const TestMode(id: 1, isTest: true),),);Copy the code
You can find more examples on the test_page_c.dart page
Push
Push name
FFRouterDelegate.of(context).pushNamed<void>(
Routes.flutterCandiesTestPageA,
);
Copy the code
Push name with arguments
- The parameter must be one
Map<String, dynamic>
FFRouterDelegate.of(context).pushNamed<void>(
Routes.flutterCandiesTestPageF.name,
arguments: Routes.flutterCandiesTestPageF.d(
<int> [1.2.3],
map: <String.String> {'ddd': 'dddd'},
testMode: const TestMode(id: 1, isTest: true),),);Copy the code
- Open – supper – the arguments
FFRouterDelegate.of(context).pushNamed<void>(
Routes.flutterCandiesTestPageF.name,
arguments: <String.dynamic> {'list': <int> [1.2.3].'map': <String.String> {'ddd': 'dddd'},
'testMode': const TestMode(id: 1, isTest: true})),Copy the code
Code Hints
You can do this using routing ‘Routes. FlutterCandiesTestPageE’, and see the code in the editor. Includes page description, structure, parameter type, parameter name, parameter mandatory.
- The default
/// 'This is test page E.'
///
/// [name] : 'flutterCandies://testPageE'
///
/// [routeName] : 'testPageE'
///
/// [description] : 'This is test page E.'
///
/// [constructors] :
///
/// TestPageE : [TestMode testMode, TestMode1 testMode1]
///
/// TestPageE.deafult : []
///
/// TestPageE.required : [TestMode(required) testMode]
///
/// [exts] : {group: Complex, order: 1}
static const String flutterCandiesTestPageE = 'flutterCandies://testPageE';
Copy the code
- Open – supper – the arguments
/// 'This is test page E.'
///
/// [name] : 'flutterCandies://testPageE'
///
/// [routeName] : 'testPageE'
///
/// [description] : 'This is test page E.'
///
/// [constructors] :
///
/// TestPageE : [TestMode testMode, TestMode1 testMode1]
///
/// TestPageE.test : []
///
/// TestPageE.requiredC : [TestMode(required) testMode]
///
/// [exts] : {group: Complex, order: 1}
static const _FlutterCandiesTestPageE flutterCandiesTestPageE =
_FlutterCandiesTestPageE();
class _FlutterCandiesTestPageE {
const _FlutterCandiesTestPageE();
String get name => 'flutterCandies://testPageE';
Map<String.dynamic> d(
{TestMode testMode = const TestMode(id: 2, isTest: false),
TestMode1 testMode1}) =>
<String.dynamic> {'testMode': testMode,
'testMode1': testMode1,
};
Map<String.dynamic> test() => const <String.dynamic> {'constructorName': 'test'};Map<String.dynamic> requiredC({@required TestMode testMode}) =>
<String.dynamic> {'testMode': testMode,
'constructorName': 'requiredC'};@override
String toString() => name;
}
Copy the code
conclusion
Routing I
In life, there are many crossroads and choices for us to make. Choice is greater than effort, sometimes think there is only one way, in fact, there can be another choice. Sometimes when you think there’s another option, there’s only one. Standing at the crossroads of life, I hope we will no longer hesitate, whether I am now, or you in the future, do not want to know after the wake.- do
Flutter
It’s been two years since I started my study alone and now I have a lot of friends to talk about,Flutter
Let me learn a lot of things, but also meet more people. I wonder how long programmers can writecode
But from chongqing light rail to do communication projects to switch to writing code, is really because of love. I think a person can do what he likes, should also be a kind of happiness. - Thank you for reading this and I hope this article has been helpful. Welcome to Join Flutter Candies, make lovely Flutter Candies. And finally, put Flutter Candies on it. It smells sweet.