Flutter使用pushNamed()返回屏幕数据错误

13

我使用pushNamed()从屏幕中获取返回数据,代码如下:

_pushToPage2() async {
    String result = await Navigator.pushNamed(context, "/page2");
    print("$tag $result");
}

但是代码存在问题,这是完整的错误堆栈:

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)

但是下面的代码可以正常工作:

_pushToPage2() async {
    String result = await Navigator.push(
         context, MaterialPageRoute(builder: (context) => Page2()));
    print("$tag $result");
}

1
你的问题现在解决了吗?还需要我提供更多帮助吗?我的回答对你有用并帮助你解决了问题吗? - ArgaPK
1
我有同样的问题,因为没有真正有效的答案,所以我认为不支持返回带有NamedRoutes的内容。 - Jonas
5个回答

16

对我来说,出现了不同的错误(type 'MaterialPageRoute<dynamic>' is not a subtype of type 'Route<String>'),我通过将返回值声明为动态类型来解决它:

dynamic result = await Navigator.of(context).pushNamed("/page");

虽然这样会失去一些类型安全性,但对我来说工作得很好。


/page 中,你如何将数据返回? - John Joe
你可以像这样返回数据:Navigator.pop(context, "任何数据"); - kaya
你如何处理一个Data对象?而不是将其序列化为字符串再反序列化回来。 - none
你可以传回任何你想要的对象,不仅限于 String - Christopher Moore
我认为这是一个相当不好的解决方案,因为它并不像你所说的那样尊重类型安全。请看一下我的解决方案! - Schnodderbalken

7

我有同样的问题。最终我找到了解决方法。将结果转换为您需要的类型。

例如:

String result = await Navigator.of(context).pushNamed("/some_route")

上面的代码将会引发异常

但是,你可以这样做:

final result = await Navigator.of(context).pushNamed("/some_route") as String;

以上代码将如预期般正常工作。


2

在路由器中,只需为MaterialPageRoute声明工作类型Page2

case "/page2":
  return MaterialPageRoute<Page2>(...};

1

提供的答案似乎都没有解决您的问题,因为它们建议您使用dynamicvar来放弃类型安全。这是一个不好的解决方法。

如果您想要在保持静态类型的情况下使用pushNamed,并且您似乎希望如此,因为您为要存储结果的变量提供了类型String,那么只有一种可能性:类型转换。

因此,不要像这样将pushNamed()用作通用方法

_pushToPage2() async {
    String result = await Navigator.pushNamed<String>(context, "/page2");
    print("$tag $result");
}

你可以这样将方法结果强制转换:

_pushToPage2() async {
    String result = await Navigator.pushNamed(context, "/page2") as String;
    print("$tag $result");
}

无法为pushNamed()方法提供类型是Navigator路由表结合的已知缺陷,如此处所述。

-2
在你的main.dart文件中,在你的main函数内定义MaterialApp小部件,然后我们在其中定义我们应用程序的路由(屏幕)。

main.dart:

void main() {
  runApp( 
    new MaterialApp( 
      home: new Screen1(), 
      routes: <String, WidgetBuilder> { 
        '/screen1': (BuildContext context) => new Screen1(), 
        '/screen2' : (BuildContext context) => new Screen2() 
      },
    )
  );
}

屏幕1:

class Screen1 extends StatelessWidget {
    @override
     Widget build(BuildContext context) {
        ...
      }
}

屏幕2:

class Screen2 extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
       ...
    }
}

要导航到屏幕,我们这样做:

Navigator.of(context).pushNamed('/screen2');

asyncawait不是必需的,但如果您正在进行异步编程,例如:您正在查询Firestore,并根据查询结果选择导航到新屏幕或选择显示错误,则需要使用它们。

更多详情请参见:Flutter中的路由和导航

编辑:

要在屏幕之间传递数据,请将参数传递给Screen2构造函数并使用Navigator.push()。请记住,在Navigator.pushNamed()中,您只传递上下文和路由名称,无法传递参数。

 Navigator.push(context, new MaterialPageRoute(
              builder: (BuildContext context) => new Screen2(new Color(0xFF66BB6A)),
            ));

屏幕2:

class Screen2 extends StatelessWidget {
     Screen2(this.color);
     final Color color;
      @override
      Widget build(BuildContext context) {
           ...
        }
 }

数据如何发送回父屏幕?我在你的代码中没有看到这样的东西。我错过了什么吗? - CopsOnRoad
你正在使用 push() 而不是 pushNamed() 传递数据,请仔细阅读问题。 - CopsOnRoad
@CopsOnRoad,我已经回答过了,我们无法从pushNamed()传递参数或数据。 - ArgaPK
所以,你的答案一开始就可以只有一行,说你不能做那个,抱歉! - CopsOnRoad
@CopsOnRoad 嗯,我也看到 OP 问如何从子屏幕获取数据,这个我在我的回答中展示了。 - ArgaPK
你的回答没有抓住重点。OP问如何从pushNamed()返回数据,但我在你的解释中没有看到你使用返回值。相反,你涉及了一个完全不同的主题:如何传递参数。 - Schnodderbalken

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接