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

Navigator operation requested with a context that does not include a Navigator

我试图在 onTap 中启动一个新屏幕,但出现以下错误:

Navigator operation requested with a context that does not include a Navigator.

我用来导航的代码是:

onTap: () { Navigator.of(context).pushNamed('/settings'); },

我在我的应用程序中设置了如下路线:

routes: <String, WidgetBuilder>{
    '/settings': (BuildContext context) => new SettingsPage(),
},

我尝试使用股票示例应用程序复制代码。我查看了 Navigator 和 Route 文档,但无法弄清楚如何使上下文包含导航器。 onTap 中使用的 context 是从传递给构建方法的参数中引用的:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

设置页面是一个class如下:

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),
  );
 }
}

我在 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')
        )
    );
  }
}

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

此示例对您构建应用有帮助吗?让我知道是否可以为您提供其他任何帮助。

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


此错误与目的地无关。发生这种情况是因为您使用了不包含 Navigator 实例的 context 作为父实例。

我该如何创建 Navigator 实例?

这通常是通过在您的小部件树中插入 MaterialAppWidgetsApp 来完成的。虽然您可以直接使用 Navigator 手动完成,但不太推荐。然后,此类小部件的所有子级都可以使用 Navigator.of(context).

访问 NavigatorState

等等,我已经有一个MaterialApp/WidgetsApp !

很可能是这种情况。但是当您使用 MaterialApp/WidgetsApp.

的父级 context 时,仍然会发生此错误

发生这种情况是因为当您执行 Navigator.of(context) 时,它将从与所用 context 关联的小部件开始。然后在小部件树中向上移动,直到找到 Navigator 或没有更多小部件。

在第一种情况下,一切都很好。在第二个中,它抛出一个

Navigator operation requested with a context that does not include a 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 传递给 MyAppbuild

问题是,MyApp 实际上是 MaterialApp 的父级。因为它是实例化 MaterialApp 的小部件!因此 MyAppBuildContext 没有 MaterialApp 作为父级!

为了解决这个问题,我们需要使用不同的context

在这种情况下,最简单的解决方案是引入一个新的小部件作为 MaterialApp 的子部件。然后使用该小部件的上下文进行 Navigator 调用。

有几种方法可以实现这一点。您可以将 home 提取到自定义 class :

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, "/"),
              ),
            ),
      ),
    );
  }
}

完整且经过测试的解决方案:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:my-app/view/main-view.dart';

class SplashView extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: Builder(
          builder: (context) => new _SplashContent(),
        ),
        routes: <String, WidgetBuilder>{
          '/main': (BuildContext context) => new MainView()}
    );
  }
}

class _SplashContent extends StatefulWidget{

  @override
  _SplashContentState createState() => new _SplashContentState();
}

class _SplashContentState extends State<_SplashContent>
    with SingleTickerProviderStateMixin {

  var _iconAnimationController;
  var _iconAnimation;

  startTimeout() async {
    var duration = const Duration(seconds: 3);
    return new Timer(duration, handleTimeout);
  }

  void handleTimeout() {
    Navigator.pushReplacementNamed(context, "/main");
  }

  @override
  void initState() {
    super.initState();

    _iconAnimationController = new AnimationController(
        vsync: this, duration: new Duration(milliseconds: 2000));

    _iconAnimation = new CurvedAnimation(
        parent: _iconAnimationController, curve: Curves.easeIn);
    _iconAnimation.addListener(() => this.setState(() {}));

    _iconAnimationController.forward();

    startTimeout();
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
        child: new Image(
          image: new AssetImage("images/logo.png"),
          width: _iconAnimation.value * 100,
          height: _iconAnimation.value * 100,
        )
    );
  }
}

大家好,我也遇到了同样的问题。这发生在我身上。我找到的解决方案非常简单。只有我所做的是在一个简单的代码中:

void main() {
  runApp(MaterialApp(
    home: YOURAPP() ,
    ),
  );
}

希望有用。

确保您当前的父控件与 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')),
        )),
      ),
    );
  }
}

正确的方式

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')),
      )),
    );
  }
}

就像脚手架一样,您可以使用 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,
    ...
  );
}

根据 this comment 如果您的导航器在 Material 内,上下文导航器推送将给出此错误。如果您创建一个新的小部件并将其分配给 material 应用程序,主导航器将起作用。

这行不通

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()),
            );
          },
        ),
      ),
    );
  }
}

这行得通

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()),
          );
        },
      ),
    );
  }
}

当您的屏幕未从其他屏幕导航时,您最初无法访问导航器,因为它未实例化 yet.So 在这种情况下,使用构建器包装您的小部件并从 there.This 为我工作。

builder: (context) => Center(
              child: RaisedButton(
                child: Text("Foo"),
                onPressed: () => Navigator.pushNamed(context, "/"),
              ),

您应该在 main.dart 中重写您的代码 来自:

void main() => runApp(MyApp());

void main() {
  runApp(MaterialApp(
  title: 'Your title',
  home: MyApp(),));}

重点是让主页 属性 成为您的第一页 这对我有用,我希望它能帮助将来的人

发生这种情况是因为尝试导航的小部件上的上下文仍在使用 material 小部件。

解决方案的简短答案是:

extract your widget

有导航到新 class,因此在调用导航时有不同的上下文

我遇到了同样的问题,通过从 MaterialApp 中删除 home 并使用 initialRoute 相反。

return MaterialApp(
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      routes: {
        '/': (context) => MyApp(),
        '/settings': (context) => SettingsPage(),
      },
    );

onTap: () => {
               Navigator.pushNamed(context, "/settings")
                },

你不能使用这个插件 https://pub.dev/packages/get/versions/2.0.2

在 MaterialApp 中分配 属性 navigatorKey: Get.key,

MaterialApp(
      navigatorKey: Get.key,
      initialRoute: "/",
     );

您可以访问Get.toNamed("Your route name");

更改您的主要功能示例:

void main() {
    runApp(
        MaterialApp(
            title: 'Your title',
            home: MyApp(),
        )
    );
}

使用这个

void main() {
  runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}

而不是这个

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

用materialapp包裹

重现代码

import 'dart:convert';

import 'package:flutter/material.dart';

void main() {
  // reproduce code
  runApp(MyApp());
  // working switch //
  // runApp(
  //
  //   MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
            body:
                Column(mainAxisAlignment: MainAxisAlignment.center, children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                height: 100,
                width: 100,
                child: ElevatedButton(
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => IntroPage(Isscar4: true)),
                    );
                  },
                  child: RichText(
                      text: TextSpan(
                    text: 'CAR',
                    style: TextStyle(
                        letterSpacing: 3,
                        color: Colors.white,
                        fontWeight: FontWeight.w400),
                    children: [
                      TextSpan(
                          text: '4',
                          style: TextStyle(
                              fontSize: 25,
                              color: Colors.red,
                              fontWeight: FontWeight.bold))
                    ],
                  )),
                ),
              ),
            ],
          ),
          SizedBox(
            height: 10,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                height: 100,
                width: 100,
                child: ElevatedButton(
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => IntroPage(Isscar4: false)),
                    );
                  },
                  child: RichText(
                      text: TextSpan(
                    text: 'BIKE',
                    style: TextStyle(
                        letterSpacing: 3,
                        color: Colors.white,
                        fontWeight: FontWeight.w400),
                    children: [
                      TextSpan(
                          text: '2',
                          style: TextStyle(
                              fontSize: 25,
                              color: Colors.red,
                              fontWeight: FontWeight.bold))
                    ],
                  )),
                ),
              ),
            ],
          )
        ])));
  }

  MaterialApp Swithwidget(istrue) {
    return MaterialApp(
      home: Scaffold(
        body: IntroPage(
          Isscar4: istrue,
        ),
      ),
    );
  }
}

class Hi extends StatelessWidget {
  const Hi({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text("df"),
    );
  }
}

class IntroPage extends StatelessWidget {
  final Isscar4;

  IntroPage({
    Key? key,
    required this.Isscar4,
  }) : super(key: key);

  List<Widget> listPagesViewModel = [];

  List<IntroModel> models = [];

  @override
  Widget build(BuildContext context) {
    List<dynamic> intro = fetchIntroApi(Isscar4);

    intro.forEach((element) {
      var element2 = element as Map<String, dynamic>;
      var cd = IntroModel.fromJson(element2);
      models.add(cd);
    });
    models.forEach((element) {
      listPagesViewModel.add(Text(""));
    });

    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          body: Container(),
        ));
  }

  List fetchIntroApi(bool bool) {
    var four = bool;
    if (four) {
      var data =
          '[ {"name_Title": "title name1","description": "description1"}, {"name_Title": "title name2","description": "description2"}, {"name_Title": "title name3","description": "description3"}, {"name_Title": "title name4","description": "description4"} ]';
      return json.decode(data);
    } else {
      var data =
          '[ {"name_Title": "title name","description": "description1"}, {"name_Title": "title name2","description": "description2"}, {"name_Title": "title name3","description": "description3"} ]';

      return json.decode(data);
    }
  }
}

class IntroModel {
  String? nameTitle;
  String? description;

  IntroModel({this.nameTitle, this.description});

  IntroModel.fromJson(Map<String, dynamic> json) {
    nameTitle = json['name_Title'];
    description = json['description'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['name_Title'] = this.nameTitle;
    data['description'] = this.description;
    return data;
  }
}

建设者( 建设者:(上下文){ return文本按钮( child: 常量文本('Bearbeiten'), onPressed:(){ Navigator.push( 语境, MaterialPageRoute(builder: (context) => const gotothesiteyouwant()), );
}); } ),