preface

Method method routing issued more than 1 years, the total feeling has some disadvantages, or use uncomfortable place.

  • It used to be routed with named parametersarguments(Map<String, dynamic>), using key to set the corresponding named parameter. The name of the parameter needs to be annotated, as shown below.
import 'package:ff_annotation_route/ff_annotation_route.dart';

@FFRoute(
  name: "fluttercandies://picswiper",
  routeName: "PicSwiper",
  argumentNames: ["index"."pics"],
  showStatusBar: false,
  pageRouteType: PageRouteType.transparent,
)
class PicSwiper extends StatefulWidget {
  final int index;
  final List<PicSwiperItem> pics;
  PicSwiper({this.index, this.pics});
  // ...
}

Copy the code
  • Because it is a named parameter, the parameter may also be optional. But in the generated code, I don’t know if you passed that argument. However, the code generated from the annotation will still try to fetch the corresponding value from arguments, which will cause the parameter to be set to NULL. So in normal use, you must pass the optional parameter in the pushName.

  • What if a page has multiple constructs? Can I choose which construct to use? It was not supported before.

  • If the construct is const, there is no way to create a const construct in the generated code.

4.0

In version 4.0, I solved the above four problems.

  • Based on theanalyzer.astLearn more about it throughastWe can just get itConstructorDeclaration, which is the definition of a construct. The code addressanalyzer/lib/dart/ast/ast.dart Below are some of the main parameters used.
abstract class ConstructorDeclaration implements ClassMember {

  /// Return the token for the 'const' keyword, or `null` if the constructor is
  /// not a const constructor.
  /// Is the construct const
  Token get constKeyword;

  /// Set the token for the 'const' keyword to the given [token].
  set constKeyword(Token token);

  /// Return the name of the constructor, or `null` if the constructor being
  /// declared is unnamed.
  /// The name of the constructor, which is null by default
  /// Factory TestPageE. Deafult (), in this case, go back to deafult
  SimpleIdentifier get name;

  /// Set the name of the constructor to the given [identifier].
  set name(SimpleIdentifier identifier);

  /// Return the parameters associated with the constructor.
  /// Returns a collection of arguments
  FormalParameterList get parameters;

  /// Set the parameters associated with the constructor to the given list of
  /// [parameters].
  set parameters(FormalParameterList parameters);
}
Copy the code
  • FormalParameteraddressanalyzer/lib/dart/ast/ast.dart This is used to describe parameters. The meaning of parameters is clear, so I won’t translate it here.
abstract class FormalParameter implements AstNode {
  /// The 'covariant' keyword, or `null` if the keyword was not used.
  Token get covariantKeyword;

  /// Return the element representing this parameter, or `null` if this
  /// parameter has not been resolved.
  ParameterElement get declaredElement;

  /// Return the name of the parameter being declared.
  SimpleIdentifier get identifier;

  /// Return `true` if this parameter was declared with the 'const' modifier.
  bool get isConst;

  /// Return `true` if this parameter was declared with the 'final' modifier.
  ///
  /// Parameters that are declared with the 'const' modifier will return
  /// `false` even though they are implicitly final.
  bool get isFinal;

  /// Return `true` if this parameter is a named parameter.
  ///
  /// Named parameters can either be required or optional.
  bool get isNamed;

  /// Return `true` if this parameter is an optional parameter.
  ///
  /// Optional parameters can either be positional or named.
  bool get isOptional;

  /// Return `true` if this parameter is both an optional and named parameter.
  bool get isOptionalNamed;

  /// Return `true` if this parameter is both an optional and positional
  /// parameter.
  bool get isOptionalPositional;

  /// Return `true` if this parameter is a positional parameter.
  ///
  /// Positional parameters can either be required or optional.
  bool get isPositional;

  /// Return `true` if this parameter is a required parameter.
  ///
  /// Required parameters can either be positional or named.
  ///
  /// Note: this will return `false` for a named parameter that is annotated
  /// with the `@required` annotation.
  bool get isRequired;

  /// Return `true` if this parameter is both a required and named parameter.
  ///
  /// Note: this will return `false` for a named parameter that is annotated
  /// with the `@required` annotation.
  bool get isRequiredNamed;

  /// Return `true` if this parameter is both a required and positional
  /// parameter.
  bool get isRequiredPositional;

  /// Return the kind of this parameter.
  @deprecated
  ParameterKind get kind;

  /// Return the annotations associated with this parameter.
  NodeList<Annotation> get metadata;

  /// The 'required' keyword, or `null` if the keyword was not used.
  Token get requiredKeyword;
}
Copy the code
  • The above 4 questions white piao official, their own logic to figure out the line,astIs very strong. But also found a problem, want to determine whether this parameterdart coreLibrary, because if it’s a class or enumeration, I’d like to have a hint for the user to setimportAddress.

Although it was possible to scan all of the DART files, this was not done because there were three references. Dart :mirrors, dart:mirrors, dart:mirrors, dart:mirrors, dart:mirrors, dart:mirrors

The method route is only referenced in dev_dependencies. Why does this affect Flutter runtime? Ff_annotation_route exposes classes for Flutter, so ff_annotation_route is compiled at runtime. Does anyone in charge know?

dev_dependencies: ff_annotation_route: path: .. /Copy the code

use

Increase the reference

Add the reference to dev_dependencies and the project/packages you need to annotate to pubspec.yaml

dev_dependencies:
  ff_annotation_route: latest-version
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.

import 'package:ff_annotation_route/ff_annotation_route.dart';

@FFRoute(
  name: 'flutterCandies://testPageE',
  routeName: 'testPageE',
  description: 'This is test page E.',
  argumentImports: <String> ['import \'package:example/src/model/test_model.dart\'; '.'import \'package:example/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 of the parameters are classes or enumerations, and you need to specify their import addresses

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:

command name description
-h, –help Print help information.
-p, –path [arguments] The directory where the command is executed, if not, is the current directory.
-rc, –route-constants Whether it is in the root projectxxx_route.dartGenerates static constants for all routes
-rh, –route-helper Dart generates xxx_route_helper.dart to help you process routes
-rn, –route-names Whether it is in the root projectxxx_route.dartGenerate the names of all routes
-s, –save Whether to save the command locally. If yes, you only need to execute the command next timeff_routeIt is ok
-na, –no-arguments FFRouteSettings will not have arguments, this is mainly for adaptation to Flutter lower versions
-g, –git package1,package2 To scan git reference packages, you need to specify the name of the package
–package Is this a package
–no-is-initial-route FFRouteSettings will not have isInitialRoute, which is intended to accommodate the higher version of Flutter
-o –output Path to the output directory of route and helper files relative to the lib folder of the main project
-rfo –routes-file-output Path of the routes file. The path is relative to the lib folder of the main project

Main.dart

  • If you run the command with the parameters, the route – helper, FFNavigatorObserver/FFRouteSettings will be generated in xxx_route_helper. Dart, used to help track pages and sets the status bar.

  • If you run a command with the parameter –route-helper, FFTransparentPageRoute will be generated in xxx_route_helper.dart, which can be used to push a transparent PageRoute.

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) {
        //when refresh web, route will as following
        // /
        // /fluttercandies:
        // /fluttercandies:/
        // /fluttercandies://mainpage
        if (kIsWeb && settings.name.startsWith('/')) {
          return onGenerateRouteHelper(
            settings.copyWith(name: settings.name.replaceFirst('/'.' ')),
            notFoundFallback:
                getRouteResult(name: Routes.fluttercandiesMainpage).widget,
          );
        }
        return onGenerateRouteHelper(settings,
            builder: (Widget child, RouteResult result) {
          if (settings.name == Routes.fluttercandiesMainpage ||
              settings.name == Routes.fluttercandiesDemogrouppage) {
            return child;
          }
          returnCommonWidget( child: child, result: result, ); }); }); }}Copy the code

Push

Push name

  Navigator.pushNamed(context, Routes.fluttercandiesMainpage /* fluttercandies://mainpage */);
Copy the code

Push name with arguments

The argument must be a Map
,>

  Navigator.pushNamed(
    context,
    Routes.flutterCandiesTestPageE,
    arguments: <String.dynamic>{
      constructorName: 'required'.'testMode': const TestMode(
        id: 100,
        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.

  /// '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

conclusion

Another problem with named routes is that arguments are not strongly typed and may not be as clear and comfortable to the user as the direct new constructor. But I don’t want to introduce additional parameters-like coupling code because you can’t have your cake and eat it too. Named routes + annotations can be used to process routes in a unified manner, and can also add some additional auxiliary functions, which is nice.

Welcome to joinFlutter CandiesTogether to produce cute little Flutter candies (QQ group: 181398081)

And finally, put Flutter Candies on it. It smells sweet.