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'
VRouteElement
s are designed like widgets: compose them to create the route you need.
To compose VRouteElement
s, 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 String
to organise your paths
Note: you often want to use a shared VNester
in different VRouteElementBuilder
s, 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 !