routes_generator 0.0.2 routes_generator: ^0.0.2 copied to clipboard
Automatically builder routes for pages.
routes_generator #
Provides source_gen Generator
to generator routes
for MaterialApp
of flutter
.
Non-intrusive, convention over configuration, only need to install and build.
Convention #
- The
routes.dart
file used to export routes and related functions toMaterialApp
. - The
pages
directory relatived toroutes.dart
contains your app views and routes, each file contains only one routing page, generator reads all.dart
files inside this directory and generate routes map intoroutes.map.dart
. - The above two conventions apply to any directory of the project.
Usage #
Basic Routes #
Add dev_dependencies
.
dev_dependencies:
routes_generator: any
Run code generation.
$ flutter pub run build_runner build
Import through routes.dart
or direct import routes.map.dart
.
// routes.dart
import 'package:flutter/widgets.dart';
import 'routes.map.dart' as p;
Map<String, WidgetBuilder> routes = p.routes;
If there are multiple routes.map.dart
, they need to be merged and used.
import 'routes.map.dart' as p;
import 'dev/routes.map.dart' as d;
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
routes: <String, WidgetBuilder>{...p.routes, ...d.routes}
);
}
}
Group Routes #
In addition to putting all routes in one Map, sometimes it is necessary to put some routes into a separate Map for special processing, such as detecting login before routing.
You need to add a private class named _RoutesGroup
and
define the supported group annotation instances, such as
class _RoutesGroup {
final String name;
const _RoutesGroup(this.name);
}
const authRequired = _RoutesGroup('authRoutes');
Add corresponding annotations on the routing page where required
@authRequired
class MySetting extends StatelessWidget {
Widget build(BuildContext context) {
// ...
}
}
Conventional annotations are private class instances.The reason for not providing annotation classes is that routing needs to be used and managed, and random group names are not allowed when grouping is specified on the page.
Parameterized #
If the page widget is parameterized, the generator will automatically inject parameters.
class ParameterizedPage extends StatelessWidget {
final String arg1;
final String arg2;
ParameterizedPage(this.arg1, {this.arg2});
}
The generated routes looks like this
Map<String, WidgetBuilder> routes = {
'/parameterized': (context) {
final Map args = ModalRoute.of(context).settings?.arguments ?? {};
return ParameterizedPage(args['arg1'], arg2: args['arg2']);
},
};
Dynamic Routes #
If the path of the page contains a directory or file name starting with an underscore (_
),
then the directory or file name will be used as a variable.
such as /dynamic/_name/_id.dart
, there are two variable in the path, name
and id
.
class DynamicPage extends StatelessWidget {
final String name;
final String id;
DynamicPage(this.name, {this.id});
}
The generated routing table is an list, which variable name ends with Dynamic
List<WidgetBuilder Function(String)> routesDynamic = [
(path) {
final reg = RegExp(r'^/dynamic/(?<name>[^\/]+)$/(?<id>[^\/]+)$');
final match = reg.firstMatch(path);
if (match == null) return null;
return (context) => DynamicPage(match.namedGroup('name'), id: match.namedGroup('id'));
},
];
That should be used in onGenerateRoute
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder = routes[settings.name];
if (builder == null) {
for (final matcher in routesDynamic) {
builder = matcher(settings.name);
if (builder != null) {
break;
}
}
}
if (builder == null) return null;
return MaterialPageRoute(settings: settings, builder: builder);
}
Configuration #
If your project structure does not conform to the convention, or want to split the route according to the environment, such as, the development app provides more pages and features, which is very useful when switching between multiple development environments. Configuration is also provided.
Basic #
The following structure is typical and conforms to the convention.
├── lib
│ ├── dev
│ │ ├── drawer.dart
│ │ ├── pages
│ │ │ └── hosts.dart
│ │ ├── routes.dart
│ │ └── routes.map.dart
│ ├── main.dart
│ ├── main_dev.dart
│ ├── pages
│ │ ├── home.dart
│ │ ├── user
│ │ │ └── settings.dart
│ │ └── setting.dart
│ ├── routes.dart
│ ├── routes.map.dart
│ └── screen
│ ├── app.dart
│ └── home.dart
Configure it in build.yaml
. The following configuration is in accordance with the convention.
Already meet basic directory split requirements.
targets:
$default:
builders:
routes_generator:
options:
ext: ".map.dart" # generated file extension
routes:
routes.dart: # routes.dart
name: "routes" # generated variable name
pages: "pages" # pages directory, relative to `routes.dart`
Change or add the configuration to fit you situation. For example,
the route directory is views
instead of pages
.
targets:
$default:
builders:
routes_generator:
options:
ext: ".my.dart" # change generated file extension
routes:
my_routes.dart: # change routes file
name: "myRoutes" # change the variable name
pages: "../views" # change pages location
dev/my_routes.dart:
name: "devRoutes"
pages: "views"
Group #
If you have defined routing grouping in the project,
you can also modify the default grouping parameters group
.
The group
need to specify the class name and grouped field name.
targets:
$default:
builders:
routes_generator:
options:
group: "MyPageRoutes.group" # change with class name and it's field name
The annotation is defined as follows.
class MyPageRoutes {
final String group;
const MyPageRoutes(this.group);
}
@MyPageRoutes(group: 'authRoutes')
class FirstPage extends StatelessWidget {
}
Ignores #
If there are non-routing page files or directories in the pages
directory,
they can be ignored by configuration
targets:
$default:
builders:
routes_generator:
options:
ignores: "**/widgets/**" # ignore all `widgets` directory in `pages`
Or configure multiple
targets:
$default:
builders:
routes_generator:
options:
ignores:
- "**/widgets/**" # ignore all `widgets` directory in `pages`
- "**.g.dart" # ignore all generated files