A Flutter package that makes navigation and routing easy.
Learn more at vrouter.dev
Here are a few things that this package will make easy:
- Automated web url handling
- Nesting routes
- Transition
- Advanced url naming
- Reacting to route changing
- Customizable pop events
- And much more...
VRouter is a widget which handles the navigation, it acts as a MaterialApp but also takes a routes arguments.
VRouter(
debugShowCheckedModeBanner: false, // VRouter acts as a MaterialApp
routes: [...], // Put your VRouteElements here
)VRouteElements are the building blocs of your routes.
Note that they are not widgets but the way you use them is very similar to widgets.
VWidget maps a path to a widget:
VWidget(path: '/login', widget: LoginScreen())VGuard allows you to take actions when the route is accessed/leaved:
VGuard(
beforeEnter: (vRedirector) async => , // Triggered when a route in stackedRoutes is first displayed
beforeUpdate: (vRedirector) async => , // Triggered when a route in stackedRoutes is displayed but changes
beforeLeave: (vRedirector, _) async => , // Triggered when VGuard is not part of a new route
stackedRoutes: [...],
);VRouteRedirector redirects from a route to another:
VRouteRedirector(path: '/old/home', redirectTo: '/home')VNester are used when you need to nested widgets instead of stacking them:
VNester(
path: '/home',
widgetBuilder: (child) => MyScaffold(body: child), // child will take the value of the widget in nestedRoutes
nestedRoutes: [
VWidget(path: 'profile', widget: ProfileScreen()), // path '/home/profile'
VWidget(path: 'settings', widget: SettingsScreen()), // path '/home/settings'
],
)VPopHandler helps you control pop events:
VPopHandler(
onPop: (vRedirector) async =>, // Called when this VRouteElement is popped
onSystemPop: (vRedirector) async =>, // Called when this VRouteElement is popped by android back button
stackedRoutes: [...],
)Navigating is easy, just access VRouter with context.vRouter and navigate:
context.vRouter.to('/home'); // Push the url '/home'
context.vRouter.toSegments(['home', 'settings']); // Push the url '/home/settings'VRouteElements are designed like widgets: compose them to create the route you need.
To compose VRouteElements, use the stackedRoutes attribute (or the nestedRoutes attribute for VNester):
// Composing a VGuard and a VWidget
VGuard(
beforeEnter: (vRedirector) async => !isLoggedIn ? vRedirector.to('/login') : null,
stackedRoutes: [
VWidget(path: '/home', widget: HomeScreen()),
],
)You can even create your own VRouteElement, as you extend VWidget. You just need to extends VRouteElementBuilder:
class HomeRoute extends VRouteElementBuilder {
static String home = '/home';
@override
List<VRouteElement> buildRoutes() {
return [
VGuard(
// LoginRoute.login = '/login' for example
beforeEnter: (vRedirector) async => !isLoggedIn ? vRedirector.to(LoginRoute.login) : null,
stackedRoutes: [
VWidget(path: home, widget: HomeScreen()),
],
),
];
}
}and then use this VRouteElement as any other:
VRouter(
routes: [
HomeRoute(),
...
],
)This can be used to:
- Separate you different routes in different VRouteElement
- Create reusable VRouteElement
- Use
static Stringto organise your paths
Note: you often want to use a shared VNester in different VRouteElementBuilders, for this specific use case, see vrouter.dev/Custom VRouteElement And Scaling
Paths can be relative: if you don’t start your path with /. If you use null, the path will be the one of the parent:
VNester(
path: '/home',
widgetBuilder: (child) => MyScaffold(body: child),
nestedRoutes: [
VWidget(path: null, widget: HomeScreen()), // Matches '/home'
VWidget(path: 'settings', widget: SettingsScreen()), // Matches '/home/settings'
]
)Paths can have path parameters, just use “:” in front of the path parameter’s name:
VWidget(path: '/user/:id', widget: UserScreen())And access it in your widgets using:
context.vRouter.pathParameters['id'];Wildcards are noted * and there are of one of two types:
- Trailing wildcards (a path ending with *) will match everything
- an in-path wildcard (a wildcard between slashes) will match one word
// Redirects any path to '/unknown'
VRouteRedirector(path: '*', redirectTo: '/unknown')Path parameters can use regex, just put the regex in parentheses. This is often used in VRedirector to redirect any unknown route:
// The path parameter name is “bookId” and it uses the regex “\d+” to match only digits
VWidget(path: r':bookId(\d+)', widget: BookScreen())Note that such a VRedirector should be used as your last route otherwise it will always be matched.
Use aliases for multiple paths:
// Matches '/settings' and '/other'
VWidget(path: '/settings', aliases: ['/other'], widget: SettingsScreen())You often want to redirect or stop the current redirection in VGuard and VPopHandler. For that purpose, you get a VRedirector:
VGuard(
beforeEnter: (vRedirector) async => !isLoggedIn ? vRedirector.to('/login') : null,
stackedRoutes: [...],
)VRouter contains data (such as the path or path parameters) that you might want to access in your widget tree. There are 2 ways of doing do:
// Use the context
context.vRouter
// Use the builder constructor of some VWidget or VNester
VWidget.builder(
path: '/:id',
builder: (context, state) => Book(id: state.pathParameters['id'] as int),
)We have just scratched the surface of what VRouter can do. Here are a few other things which you might like.
Maybe you want to redirect people to a certain part of your app when they first launch it, then use initialUrl:
VRouter(
initialUrl: '/home',
routes: [...],
)By default, VRouter shows logs of every navigation events.
You can remove these logs using VLogs.none:
VRouter(
logs: VLogs.none,
routes: [...],
);You might have to access a deeply nested VRouteElement and don’t want to have to write the full url. Just give a name to this VRouteElement:
VWidget(path: 'something', widget: SomeWidget(), name: 'deep')And navigate using toNamed:
context.vRouter.toNamed('deep');You can either specify a default transition in VRouter, or a custom one in VWidget or VNester
VRouter(
// Default transition
buildTransition: (animation1, _, child) => FadeTransition(opacity: animation1, child: child),
routes: [
// The custom ScaleTransition will play for '/user'
VWidget(
path: '/user',
widget: UsersScreen(),
buildTransition: (animation1, _, child) => ScaleTransition(scale: animation1, child: child),
)
// The default FadeTransition will play for '/settings'
VWidget(path: '/settings', widget: SettingsScreen()),
],
)There is so much more that this package can do, check out the example or have a look at the vrouter.dev website for more documentation and more examples.
Also don’t hesitate to join us on discord !