Difference between onGenerateRoute and routes in Flutter
NB (see comments below answer):
There is no bug, just bad usage by the issue reporter. It is caused because he didn't pass the settings object along to the new MaterialPageRoute returned by the onGenerateRoute method (see the issue's final comments). [...]
Original answer mentionning a "bug":
Without diving into any details those two properties do the same thing, but as @Alireza noted routes
is checked first.
Also, using onGenerateRoute
gives you a single place to add your custom business logic before pushing new routes (pages). For example, if you want to do some initializations.
routes property:
When a named route is pushed with Navigator.pushNamed, the route name is looked up in this map. If the name is present, the associated WidgetBuilder is used to construct a MaterialPageRoute that performs an appropriate transition, including Hero animations, to the new route.
onGenerateRoute property:
The route generator callback used when the app is navigated to a named route. ... This is used if routes does not contain the requested route.
IMPORTANT:
What you really want to be aware of is a known bug in onGenerateRoute
property.
The problem is that if you use onGenerateRoute
to create named routes you won't be able to get the name of that route from RouteSettings object in your page. (Arguments attached to the settings object are fine though)
In other words:
Widget build(BuildContext context) {
ModalRoute.of(context).settings.name == null; //bug
ModalRoute.of(context).settings.arguments != null; //ok
...
This may affect you in case you would like to know the name of the current route. For example, if you want to pop some screens:
navigator.popUntil(ModalRoute.withName('/login'));
Therefore, until this problem is resolved, I recommend using the routes:
property.
routes
is static and doesn't offer functionalities like passing an argument to the widget, implementing a different PageRoute
etc, which is why onGenerateRoute
exists.
In the given code, you'll find that how using onGenerateRoute
property, you can parse an argument and send it over, which isn't possible with simple routes
.
FooPage
is navigated through routes
and BarPage
through onGenerateRoute
.
Initial setup in MaterialApp
.
void main() {
runApp(
MaterialApp(
routes: {
'/': (_) => HomePage(), // You can also use MaterialApp's `home` property instead of '/'
'/foo': (_) => FooPage(), // No way to pass an argument to FooPage.
},
onGenerateRoute: (settings) {
if (settings.name == '/bar') {
final value = settings.arguments as int; // Retrieve the value.
return MaterialPageRoute(builder: (_) => BarPage(value)); // Pass it to BarPage.
}
return null; // Let `onUnknownRoute` handle this behavior.
},
),
);
}
home.dart
:
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('HomePage')),
body: Center(
child: Column(
children: [
ElevatedButton(
onPressed: () => Navigator.pushNamed(context, '/foo'),
child: Text('Go to FooPage'),
),
ElevatedButton(
onPressed: () => Navigator.pushNamed(context, '/bar', arguments: 42), // Passing argument
child: Text('Go to BarPage'),
),
],
),
),
);
}
}
foo.dart
class FooPage extends StatelessWidget {
@override
Widget build(_) => Scaffold(appBar: AppBar(title: Text('FooPage')));
}
And bar.dart
:
class BarPage extends StatelessWidget {
final int value;
BarPage(this.value);
@override
Widget build(_) => Scaffold(appBar: AppBar(title: Text('BarPage, value = $value')));
}
Screenshot (for reference)