与不包括导航器的上下文一起请求的导航器操作

我试图在 onTap 中启动一个新屏幕,但是我得到了以下错误:

请求的导航器操作,其上下文不包括 领航员。

我用来导航的代码是:

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

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

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

我尝试使用股票示例应用程序复制代码。我已经查看了 Navigator 和 Route 文档,但不知道如何使上下文包含 Navigator。OnTap 中使用的 context是从传递到构建方法中的参数引用的:

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),
);
}
}
133525 次浏览

我在 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中,或者将该子树提取到类中。并使用新的 BuildContext访问 Navigator


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

那么如何创建 Navigator 实例呢?

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

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

很有可能。但是,当您使用 MaterialApp/WidgetsApp的父级 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传递给 MyAppbuild

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

或者你可以使用 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() ,
),
);
}

希望能派上用场。

确保您当前的父窗口小部件不具有材质应用程序的相同级别

错误的方式

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

根据 此评论,如果你的导航器在物质上下文导航器推将会给出这个错误。如果你创建一个新的小部件,并将其分配给材料应用程序家庭导航器将工作。

没用的

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

当您的屏幕没有从其他屏幕导航时,您最初不能访问导航器,因为它还没有实例化。所以在这种情况下,用构建器包装您的小部件并从中提取上下文。这招对我很管用。

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

重点是让 home 属性成为你的第一页 这对我很有用,我希望将来它能帮到别人

之所以会发生这种情况,是因为试图导航的小部件上的上下文仍在使用材料小部件。

解决方案的简短答案是:

提取你的小部件

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

我也面临着同样的问题,通过从 材料应用程序中移除 并使用 初始路线解决了这个问题。

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

在材料应用程序分配属性导航键: 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());}

用材料包装

复制代码

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;
}
}
Builder(
builder: (context) {
return TextButton(
child: const Text('Bearbeiten'),
onPressed:(){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const gotothesiteyouwant()),
);
});
}
),

很简单

而不是使用这个正常的代码

`runApp(BasicBankingSystem());`

用“材料应用程序”把它包装起来

runApp(MaterialApp(home: BasicBankingSystem()));
class Splash extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Splash Screen',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: MyState(),
debugShowCheckedModeBanner: false,
);
}
    

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


class MyState extends StatefulWidget{
@override
_MyHomePageState createState() => _MyHomePageState();
}


class _MyHomePageState extends State<MyState> {
@override
void initState() {
super.initState();
Timer(Duration(seconds: 3),
()=>Navigator.pushReplacement(context,
MaterialPageRoute(builder:
(context) =>
Login()
)
)
);
}
    

@override
Widget build(BuildContext context) {
return Center(
child:  Column(
mainAxisAlignment:   MainAxisAlignment.center ,
children: [
Container(
child:
Image.asset("assets/images/herosplash.png"),
          

),
],
),
);
}
}

在这里,所有您需要的是使材料应用程序成为您的构建的父级。这是因为您用来导航到不同屏幕的上下文是查找作为构建的父节点的 Materials ialApp 或 WidgetApp。

因为在您的情况下,情况正好相反,因此您需要通过调用一个新的无状态小部件(它的父部件是 aterialApp)或者在 MaterialApp中简单地使用 Builder 作为 home: Builder来修改它。

希望这个能帮上忙!