简而言之: 将需要访问Navigator
的小部件包装到一个Builder
中,或将该子树提取到一个类中。并使用新的BuildContext
来访问Navigator
。
这个错误与目标无关。它是因为你使用了一个没有包含导航器实例作为父级的上下文。
那我怎么创建导航器实例呢?
通常情况下,你可以在 Widget 树中插入一个 MaterialApp
或 WidgetsApp
来实现。虽然你也可以手动使用 Navigator
直接创建,但不建议这样做。然后,这些 widget 的所有子代都可以使用 Navigator.of(context)
访问 NavigatorState
了。
等等,我已经有一个 MaterialApp
/WidgetsApp
了!
这很可能是情况所在。但是当你使用的上下文是 MaterialApp
/WidgetsApp
的父级时,仍然会发生此错误。
这是因为当你执行 Navigator.of(context)
时,它将从与所使用的 context
关联的 widget 开始,然后向上遍历 widget 树,直到它找到一个 Navigator
或者没有更多的 widget 可以迭代为止。
如果是第一种情况,那就没问题了。如果是第二种情况,就会抛出异常。
导航器操作请求的上下文中不包含导航器。
那么,我该如何修复它呢?
首先,让我们重现这个错误:
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, "/"),
我们使用了由MyApp
的build
传递的context
。
问题是,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, "/"),
),
),
),
);
}
}