请求导航器操作的上下文不包含导航器

jul*_*cer 33 flutter

我正在尝试在onTap中启动一个新屏幕,但是我收到以下错误:

请求导航器操作的上下文不包含导航器.

我用来导航的代码是:

onTap: () { Navigator.of(context).pushNamed('/settings'); },
Run Code Online (Sandbox Code Playgroud)

我在我的应用程序中设置了一条路线,如下所示:

routes: <String, WidgetBuilder>{
    '/settings': (BuildContext context) => new SettingsPage(),
},
Run Code Online (Sandbox Code Playgroud)

我试图使用stocks示例应用程序复制代码.我查看了Navigator和Route文档,但无法弄清楚如何将上下文包含在Navigator中.的context在使用的onTap感从传递到构建方法中的参数引用:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
Run Code Online (Sandbox Code Playgroud)

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),
  );
 }
}
Run Code Online (Sandbox Code Playgroud)

Rém*_*let 86

TLDR:将需要访问的窗口小部件包装Navigator到一个Builder或将该子树提取到一个类中.并使用新BuildContext访问Navigator.


此错误与目标无关.之所以发生这种情况,是因为您使用了context不包含Navigator实例的父项.

如何创建Navigator实例呢?

这通常通过在窗口小部件树中插入a MaterialApp或来完成WidgetApp.虽然你可以Navigator直接使用手动但不太推荐.然后,这样的小部件的所有孩子都可以NavigatorState使用Navigator.of(context).

等等,我已经有了MaterialApp/ WidgetApp!

这种情况最有可能发生.但是,如果您使用的contextMaterialApp/ 的父级,则仍会发生此错误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, "/"),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

此示例创建一个按钮,尝试在单击时转到'/',但会抛出异常.

请注意这里

  onPressed: () => Navigator.pushNamed(context, "/"),
Run Code Online (Sandbox Code Playgroud)

我们使用context通过向传递buildMyApp.

问题是,MyApp实际上是父母的MaterialApp.因为它是实例化的小部件MaterialApp!因此MyAppBuildContext不具有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, "/"),
        ),
      );
  }
}
Run Code Online (Sandbox Code Playgroud)

或者您可以使用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, "/"),
              ),
            ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案看起来不错。但是如果我需要使用initialRoute而不是home怎么办? (13认同)
  • @GrumpyRodriguez 这个答案假设您想在家庭中使用单个小部件。但此解决方案不适用于您使用路由器的情况,因此需要为您拥有的每条路由实现某种基本小部件。例如,如果您需要在需要使用导航器的公共小部件中初始化侦听器,则这将不起作用,因为没有适用于所有路由的公共小部件。小部件被复制,您的侦听器也是如此。 (9认同)

小智 24

嘿伙计们,我有同样的问题。这发生在我身上。我发现的解决方案非常简单。只有我所做的是一个简单的代码:

void main() {
  runApp(MaterialApp(
    home: YOURAPP() ,
    ),
  );
}
Run Code Online (Sandbox Code Playgroud)

我希望有用。

  • 难道我们不应该在小部件树中只使用一次“MacialApp”小部件吗? (4认同)
  • 这是最简单的解决方案。说到重点了! (2认同)

Mah*_*eja 17

确保您当前的父小部件与 MaterialApp 不在同一级别

错误道

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: Text('Title'),
        ),
        body: Center(
            child: Padding(
          padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
          child: RaisedButton(
              onPressed: () {
                //wrong way: use context in same level tree with MaterialApp
                Navigator.push(context,
                    MaterialPageRoute(builder: (context) => ScanScreen()));
              },
              child: const Text('SCAN')),
        )),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

正确的方法

void main() => runApp(MaterialApp(
      title: "App",
      home: HomeScreen(),
    ));

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text('Title'),
      ),
      body: Center(
          child: Padding(
        padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
        child: RaisedButton(
            onPressed: () {
            //right way: use context in below level tree with MaterialApp
              Navigator.push(context,
                  MaterialPageRoute(builder: (context) => ScanScreen()));
            },
            child: const Text('SCAN')),
      )),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Rai*_*ann 11

我在flutter应用程序中设置了这个简单的路由示例:

import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      home: new MyHomePage(),
      routes: <String, WidgetBuilder>{
        '/settings': (BuildContext context) => new SettingsPage(),
      },
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('TestProject'),
      ),
      body: new Center(
        child: new FlatButton(
          child: const Text('Go to Settings'),
          onPressed: () => Navigator.of(context).pushNamed('/settings')
        )
      )
    );
  }
}

class SettingsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('SettingsPage'),
        ),
        body: new Center(
            child: new Text('Settings')
        )
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,SettingsPage扩展了StatelessWidget而不是Navigator.我无法重现您的错误.

此示例是否可以帮助您构建应用程序?如果我可以帮助你,请告诉我.

  • 也许你遇到了https://github.com/flutter/flutter/issues/15919 (4认同)

小智 9

你应该在 main.dart FROM 中重写你的代码:

void main() => runApp(MyApp());
Run Code Online (Sandbox Code Playgroud)

void main() {
  runApp(MaterialApp(
  title: 'Your title',
  home: MyApp(),));}
Run Code Online (Sandbox Code Playgroud)

关键是让房产成为你的第一页,这对我有用,我希望它会在未来对某人有所帮助


小智 7

就像使用 Scaffold 一样,您可以使用GlobalKey. 它不需要上下文。

final _navKey = GlobalKey<NavigatorState>();

void _navigateToLogin() {
  _navKey.currentState.popUntil((r) => r.isFirst);
  _navKey.currentState.pushReplacementNamed(LoginRoute.name);
}

@override
Widget build(BuildContext context) {
  return MaterialApp(
    navigatorKey: _navKey,
    ...
  );
}
Run Code Online (Sandbox Code Playgroud)


lak*_*man 5

根据此评论,如果您的导航器位于材质上下文中,导航器推送将给出此错误。如果您创建一个新的小部件并将其分配给材质应用程序主页导航器将起作用。

这行不通

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text("Title"),
        ),
        body: new Center(child: new Text("Click Me")),
        floatingActionButton: new FloatingActionButton(
          child: new Icon(Icons.add),
          backgroundColor: Colors.orange,
          onPressed: () {
            print("Clicked");
            Navigator.push(
              context,
              new MaterialPageRoute(builder: (context) => new AddTaskScreen()),
            );
          },
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

这会起作用

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: new HomeScreen());
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Title"),
      ),
      body: new Center(child: new Text("Click Me")),
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.add),
        backgroundColor: Colors.orange,
        onPressed: () {
          print("Clicked");
          Navigator.push(
            context,
            new MaterialPageRoute(builder: (context) => new AddTaskScreen()),
          );
        },
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)