TLDR:将需要访问Navigator 的小部件包装成Builder 或将该子树提取到一个类中。并使用新的BuildContext 访问Navigator。
此错误与目的地无关。发生这种情况是因为您使用了不包含 Navigator 实例作为父级的 context。
那我该如何创建一个 Navigator 实例呢?
这通常通过在您的小部件树中插入MaterialApp 或WidgetApp 来完成。虽然您可以直接使用Navigator 手动完成,但不太推荐。然后,此类小部件的所有子级都可以使用Navigator.of(context) 访问NavigatorState。
等等,我已经有MaterialApp/WidgetApp了!
很可能是这种情况。但是,当您使用作为 MaterialApp/WidgetApp 的父级的 context 时,仍然会发生此错误。
发生这种情况是因为当您执行Navigator.of(context) 时,它将从与使用的context 关联的小部件开始。然后在小部件树中向上移动,直到找到Navigator 或没有更多小部件。
在第一种情况下,一切都很好。在第二个中,它抛出一个
使用不包含导航器的上下文请求导航器操作。
那么,我该如何解决呢?
首先,让我们重现这个错误:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
),
);
}
}
此示例创建一个按钮,该按钮尝试在单击时转到“/”,但会引发异常。
注意这里的
onPressed: () => Navigator.pushNamed(context, "/"),
我们使用context 传递给build 的MyApp。
问题是,MyApp 实际上是MaterialApp 的父级。因为它是实例化MaterialApp 的小部件!因此MyApp 的BuildContext 没有MaterialApp 作为父级!
为了解决这个问题,我们需要使用不同的context。
在这种情况下,最简单的解决方案是引入一个新小部件作为MaterialApp 的子小部件。然后使用该小部件的上下文进行Navigator 调用。
有几种方法可以实现这一点。您可以将home 提取到自定义类中:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHome()
);
}
}
class MyHome extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
);
}
}
或者你可以使用Builder:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context) => Center(
child: RaisedButton(
child: Text("Foo"),
onPressed: () => Navigator.pushNamed(context, "/"),
),
),
),
);
}
}