Reputation: 334
I use pushNamed() to get return data from screen like this:
_pushToPage2() async {
String result = await Navigator.pushNamed(context, "/page2");
print("$tag $result");
}
But there was something wrong with the code, this the full error stack trace:
E/flutter: [ERROR:flutter/shell/common/shell.cc(181)] Dart Error: Unhandled exception:
type 'MaterialPageRoute' is not a subtype of type 'Route'
0 NavigatorState._routeNamed (package:flutter/src/widgets/navigator.dart:1408:14)
1 NavigatorState.pushNamed (package:flutter/src/widgets/navigator.dart:1454:20)
2 _MyHomePageState._pushToPage2 (file:///Users/wang/flutter_project/flutter_navigation/lib/main.dart:113:50)
3 _MyHomePageState.build. (file:///Users/wang/flutter_project/flutter_navigation/lib/main.dart:58:19)
4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
5 _InkResponseState.build. (package:flutter/src/material/ink_well.dart:562:30)
6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
7 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
8 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
9 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
10 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
11 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
12 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:143:19)
13 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
14 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
15 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
16 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
17 _invoke1 (dart:ui/hooks.dart:153:13)
18 _dispatchPointerDataPacket (dart:ui/hooks.dart:107:5)
But the following code is working properly:
_pushToPage2() async {
String result = await Navigator.push(
context, MaterialPageRoute(builder: (context) => Page2()));
print("$tag $result");
}
Upvotes: 14
Views: 9147
Reputation: 3477
None of the provided answers seem to address your issue as they advice you to abandon type safety by using dynamic
or var
. This is a bad workaround.
If you intent to use pushNamed
while maintaining static typing, which you seem to want as you are providing the type String
for the variable you want to store the result in, there is only one possibility: type casting.
So instead of using pushNamed()
as a generic method like this:
_pushToPage2() async {
String result = await Navigator.pushNamed<String>(context, "/page2");
print("$tag $result");
}
you typecast the method result like this:
_pushToPage2() async {
String result = await Navigator.pushNamed(context, "/page2") as String;
print("$tag $result");
}
Not being able to provide a type to the pushNamed()
method is a known deficiency of Navigator
in combination with route tables
, as stated here.
Upvotes: 1
Reputation: 91
I have a same problem. And finally I found a solution. Cast your result to your type.
For example:
String result = await Navigator.of(context).pushNamed("/some_route")
The code above will raise the exception.
But, you can do like this:
final result = await Navigator.of(context).pushNamed("/some_route") as String;
The code above will work as expected.
Upvotes: 9
Reputation: 33
Just declare the working type Page2
for MaterialPageRoute
in the router
case "/page2":
return MaterialPageRoute<Page2>(...};
Upvotes: 3
Reputation: 3383
For me, the error was a different one (type 'MaterialPageRoute<dynamic>' is not a subtype of type 'Route<String>'
), and I solved it by declaring the returning value as a dynamic type:
dynamic result = await Navigator.of(context).pushNamed("/page");
While this loses some type safety, it works fine for me.
Upvotes: 16
Reputation: 455
In your main.dart file and inside your main Function define MaterialApp widget, and inside it we define routes (screens) of our App.
main.dart:
void main() {
runApp(
new MaterialApp(
home: new Screen1(),
routes: <String, WidgetBuilder> {
'/screen1': (BuildContext context) => new Screen1(),
'/screen2' : (BuildContext context) => new Screen2()
},
)
);
}
Screen1:
class Screen1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
...
}
}
Screen2:
class Screen2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
...
}
}
And to Navigate to screens we do:
Navigator.of(context).pushNamed('/screen2');
async
and awiat
is not needed but if you are doing async programming for e.g; you are querying Firestore and on the basis of the result of query, you choose to navigate to the new screen or choose to show the error.
For more details: routing and navigation in flutter
Edit:
To pass data between Screens, pass the argument to the Screen2 constructor and use Navigator.push()
. Remember that in Navigator.pushNamed()
you pass context and route name only, and you can't pass arguments in it.
Navigator.push(context, new MaterialPageRoute(
builder: (BuildContext context) => new Screen2(new Color(0xFF66BB6A)),
));
Screen2:
class Screen2 extends StatelessWidget {
Screen2(this.color);
final Color color;
@override
Widget build(BuildContext context) {
...
}
}
Upvotes: -2