- Follow the setup steps for catalyst_builder.
- Follow the setup steps for explorator.
void main() {
// Create an instance of the service container
var container = ServiceContainer();
container
// Extension method from the explorator package
..useExplorator()
..setupExplorator(
routeBuilder: MaterialRouteBuilder(),
)
..boot();
// Run the app
runApp(MyApp(container));
}
class MyApp extends StatelessWidget {
/// Inject the container
final AbstractServiceContainer _container;
const MyApp(this._container, {super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// Use the navigator key
navigatorKey: _container.resolve<GlobalKey<NavigatorState>>(),
// Set the initial route.
initialRoute: '/home/HelloFlutter',
// Use the RouteResolver for generating routes
onGenerateRoute: _container
.resolve<RouteResolver>()
.resolveRoute,
);
}
}
After you set up the routing, you can register routes.
/// Create a class that implements the RouteProvider and add the @Service annotation with a tag.
@Service(tags: [RouteProvider.tag])
class HomeRouteProvider implements RouteProvider {
@override
List<RegisteredRoute> get routes =>
[
// Return your routes
RegisteredRoute(
path: r'/home/{name}',
// The builder should return a function that accepts a container (ServiceContainer from above)
// and returns a WidgetBuilder. Since we have the container, we can use DI to get the instance
// of our widget 🙌.
builder: (container) => (ctx) => container.resolve<MyHomePage>(),
)
];
}
/// Decorate your Widget with the Service Annotation.
/// ServiceLifetime.transient is required to create always a fresh instance of this widget.
@Service(lifetime: ServiceLifetime.transient)
class MyHomePage extends StatefulWidget {
/// RouteArguments contains the parameters and other settings of the route.
final RouteArguments arguments;
const MyHomePage(this.arguments, {super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
/// Access the name variable from the route. For example "HelloFlutter"
title: Text(widget.arguments.pathVariables['name'] ?? 'Missing name'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme
.of(context)
.textTheme
.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}To navigate between routes you can use the Routing class or the default Navigator.of(context).xxxNamed methods.
You find a full example in the example directory.
As you can see in the example above, you can specify variables in the route. The format is {name}
or {name:REGEXP} where REGEXP is a regular expression string.
| Route | Valid | Invalid | Path variables (valid example) |
|---|---|---|---|
/home |
/home |
/home/foo |
- |
/home/{name} |
/home/foo, /home/bar |
/home/foo/bar |
name=foo, name=bar |
/home/{name:.+} |
/home/foo, /home/foo/bar |
/other |
name=foo, name=foo/bar |
/user/{userId:\d} |
/user/1, /user/2 |
/user/12, /user/admin |
userId=1, userId=2 |
/user/{userId:\d+} |
/user/1, /user/2, /user/12 |
/user/admin |
userId=1, userId=2 |
Query parameters are supported in all examples above.
You can access path variables and query parameters when injecting the RouteArguments object.
While you develop your app, you can use the following command to watch for changes and update the routing / ServiceContainer automatically
dart run build_runner watch --delete-conflicting-outputsWhen building for production you can use this command before running flutter build:
dart run build_runner build --delete-conflicting-outputsCheck out the "under the hood" doc.