import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// 主方法
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Navigator跳转页面')),
body: Center(
child: GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext ctx) => FirstPage()));
},
child: Text('Hello World!',textDirection: TextDirection.ltr),
),
),
)
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Text('我是第二个页面',textDirection: TextDirection.ltr),
),
);
}
}
在使用Navigator.of的时候,传入context时会报错。
Navigator operation requested with a context that does not include a Navigator
The context used to push or pop routes from the Navigator must be that of a widget that is a
descendant of a Navigator widget.
看样子就是传入的context不对,刚入坑对BuildContext也不熟悉,只能看看BuildContext具体是什么意思了。下面是对BuildContext类的翻译,反正意思是那个意思。
表示了一个widget在widget树中的位置引用。
些类提供了一组可以使用StatelessWidget.build方法和State对象方法的方法。
BuildContext对象将传入到WidgetBuilder函数里(例如StatelessWidget.build),并且可以从State.context成员变量中获取。一些静态函数(如showDialog,Theme.of等等)也采用构建上下文,以便能使用widget执行操作,或者获取给定的上下文数据。
每个widget都有自己的BuildContext,它成为了StatelessWidget.build或State.build函数返回的widget的父级。(同样,RenderObjectWidgets的任何子代的父代)
特别是,这意味着在build方法中,build方法的widget的构建上下文,与build方法返回的widget的构建上下文不一样。这可能会导致一些棘手的问题。例如,Theme.of(context)寻找给定上下文中最近的封装了Theme的部件。如果一个Q部件的build方法,在返回的widget树中包含了Theme部件,并将它自己的context传入Theme.of方法中,Q部件的build方法将不会找到Theme对象,相反,它会找到Q部分祖先的Theme对象。如果需要返回树的子部分的构建上下文,可以使用Builder部件:Builder本身的上下文对象将会作为参数传到Builder.builder的回调函数中。
举例来说,在下面的代码片段中,ScaffoldState.showSnackBar方法在Scaffold部件中的Builder本身的回调函数中调用,如果不使用Builder部件,而是使用build方法的context参数,Scaffold部件不会被找到,Scaffold.of函数方法会返回null。
@override Widget build(BuildContext context) { // 这里, Scaffold.of(context) 返回 null return Scaffold( appBar: AppBar(title: Text('Demo')), body: Builder( builder: (BuildContext context) { return FlatButton( child: Text('BUTTON'), onPressed: () { // 这里, Scaffold.of(context) 返回当前创建的Scaffold Scaffold.of(context).showSnackBar(SnackBar( content: Text('Hello.') )); } ); } ) ); }
随着widget在树上的移动,特定的widget的BuildContext可以随时改变位置。因为这个原因,类方法中返回的值不应该在执行单个同步方法后被缓存。
BuildContext实际上就是Element对象,BuildContext接口是用来阻止直接操作Element对象的。
其实就是讲了两种获取context的方法,一种就是widget的build方法的参数来获取,还有一种就是使用Builder部件参数的builder函数回调参数,来获取一个Builder自身的context对象。
那为什么会报错呢?我不是使用了build方法中的context对象来寻找Navigator对象了吗?回头翻看了一下Navigator.of的源码:
这种情况应该是使用context找符合要求的祖先navigator没有找到,并且我们的MyApp还继承了StatelessWidget,所以更不符合要求了,先按照这种情况,我们将Scaffold抽出来看看。
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// 主方法
@override
Widget build(BuildContext context) {
print(context.findRootAncestorStateOfType());
return MaterialApp(
home: HomePage()
);
}
}
class HomePage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Navigator跳转页面')),
body: Center(
child: GestureDetector(
onTap: () {
print(context.findRootAncestorStateOfType());
Navigator.of(context,rootNavigator: true).push(MaterialPageRoute(builder: (BuildContext ctx) => FirstPage()));
},
child: Text('Hello World!',textDirection: TextDirection.ltr),
),
),
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Text('我是第二个页面',textDirection: TextDirection.ltr),
),
);
}
}
还有一种方法就是使用Builder来获取context,先上一版改过的代码:
class MyApp extends StatelessWidget {
// 主方法
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (context){
// 这里使用builder回调获取Builder本身的context
return Scaffold(
appBar: AppBar(title: Text('Navigator跳转页面')),
body: Center(
child: GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext ctx) => FirstPage()));
},
child: Text('Hello World!',textDirection: TextDirection.ltr),
),
),
);
},
)
);
}
}