Reputation: 1672
I'm trying to navigate to another page using a named route:
... RaisedButton(
child: Text('Get image'),
onPressed: () => Navigator.pushNamed<String>(
context, '/second'),...
but get the error
> I/flutter (12439): ══╡ EXCEPTION CAUGHT BY GESTURE
> ╞═══════════════════════════════════════════════════════════════════
> I/flutter (12439): The following assertion was thrown while handling a gesture:
> I/flutter (12439): type 'MaterialPageRoute<dynamic>' is not a subtype of type 'Route<String>'
> I/flutter (12439): Either the assertion indicates an error in the framework itself, or we should provide substantially
> I/flutter (12439): more information in this error message to help you determine and fix the underlying cause.
> I/flutter (12439): In either case, please report this assertion by filing a bug on GitHub:
> I/flutter (12439): https://github.com/flutter/flutter/issues/new?template=BUG.md
> I/flutter (12439): When the exception was thrown, this was the stack:
> I/flutter (12439): #0 NavigatorState._routeNamed package:flutter/…/widgets/navigator.dart:1426
> I/flutter (12439): #1 NavigatorState.pushNamed package:flutter/…/widgets/navigator.dart:1473
> I/flutter (12439): #2 Navigator.pushNamed package:flutter/…/widgets/navigator.dart:740
> I/flutter (12439): #3 _CompleterState.build.<anonymous closure> package:my_package/completer.dart:205
The route is defined in the homepage:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'XXXX',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Completer(),
routes: {
'/second': (BuildContext context) => SecondPage(),
},
onUnknownRoute: (RouteSettings settings) {
return MaterialPageRoute(
builder: (BuildContext context) => Completer(),
);
},
);
}
}
I couldn't find anything on this error message, so I seem to have generated an error that no-one else has seen before.
I'm slowly hacking away at the code to simplify it to the bare minimum, to work out what I've done wrong, but any pointers would be appreciated.
Upvotes: 37
Views: 25257
Reputation: 61
In my case, I made it work by changing <String>
to <dynamic>
, so it looked like this:
Navigator.pushNamed<dynamic>(context, '/second'),
Upvotes: 2
Reputation: 189
Found out that Navigator.pushNamed(context, '/second') as String
works fine with named routes, this would be useful when returning data from a second named page and using it a bit more strictly typed (as everything should be)
Upvotes: 10
Reputation: 305
It does make sense to have the type hints, it helps with debugging and lets the IDE flag when the type is not what you expect. (Big fan of strong typing where possible)
And you CAN do this with your named routes - Hooray!
You've implemented your route handling with the routes
attribute of the MaterialApp
but as you have found there is nowhere to add a return type of the route you are creating.
routes: {
'/second': (BuildContext context) => SecondPage(),
}
This means any instance passed to it must have return type dynamic
and throws an error for anything else.
In order to specify the return type, it takes a little more code and the use of the onGenerateRoute
property of MaterialApp
:
MaterialApp(
// ... All the other properties
// You can still have the simple 'routes' version at the same time
// so don't need to implement all routes in long-form below
routes: <String, WidgetBuilder>{
'/first': (BuildContext context) => FirstPage();
},
onGenerateRoute: (RouteSettings settings) {
final String routeName = settings.name;
final Map<String, dynamic> args = settings.arguments; // Get any arguments passed to the route
switch (routeName) {
case '/second':
// Set the Route return value here to correspond with pushNamed<String> for example
return MaterialPageRoute<String>(
builder: (BuildContext context) => SecondPage(arg1: args["arg1"]);
settings: settings,
);
}
)
This will now handle the pushNamed<String>('/second')
- And There Was Much Rejoicing!
Upvotes: 13
Reputation: 52534
Change this:
MyType result = await Navigator.pushNamed(
context,
MyPage.routeName,
arguments: PageArguments(myArg);
to:
var result = await Navigator.pushNamed(
context,
MyPage.routeName,
arguments: PageArguments(myArg);
Upvotes: 20
Reputation: 1672
Blindingly obvious in hindsight.
I had added the String type-hint in Navigator.pushNamed<String>()
as I thought I could receive a typed value back from the call. Removing that and receiving it into a var solved the problem.
Leaving this up for anyone else who gets themselves into the same state.
Upvotes: 60