请求的导航器操作的上下文不包含导航器
问题内容:
我正在尝试在onTap中启动新屏幕,但出现以下错误:
请求的导航器操作使用了不包含导航器的上下文。
我用来导航的代码是:
onTap: () { Navigator.of(context).pushNamed('/settings'); },
我已经在我的应用程序中设置了一条路线,如下所示:
routes: <String, WidgetBuilder>{
'/settings': (BuildContext context) => new SettingsPage(),
},
我尝试使用stocks示例应用程序复制代码。我查看了Navigator and
Route文档,但无法弄清楚如何使上下文包含Navigator。的context
在使用的onTap感从传递到构建方法中的参数引用:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
SettingsPage是如下类:
class SettingsPage extends Navigator {
Widget buildAppBar(BuildContext context) {
return new AppBar(
title: const Text('Settings')
);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: buildAppBar(context),
);
}
}
问题答案:
TLDR
:将需要访问的小部件包装Navigator
到Builder
或将子树提取到类中。并使用新BuildContext
的访问Navigator
。
此错误与目的地无关。发生这种情况是因为您使用了一个context
不包含Navigator
实例的父对象。
然后如何创建Navigator实例?
这通常是通过在窗口小部件树中插入MaterialApp
或来完成的WidgetApp
。虽然您可以Navigator
直接使用手动方式进行操作,但建议不要这样做。然后,此类小部件的所有子级都可以NavigatorState
使用进行访问Navigator.of(context)
。
等等,我已经有一个MaterialApp
/ WidgetApp
!
很有可能是这种情况。但是,当您使用/ context
的父级时,仍然会发生此错误。MaterialApp``WidgetApp
发生这种情况是因为,当您这样做时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
‘s
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, "/"),
),
),
),
);
}
}