Flutter应用中的页面跳转实现由Navigator,Route来实现.
Navigator
Navigator是一个路由管理的widget,它通过一个栈来管理一个路由widget集合。通常当前屏幕显示的页面就是栈顶的路由。Navigator提供了一系列方法来管理路由栈,在此我们只介绍其最常用的两个方法:
Future push(BuildContext context, Route route)
将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据。
bool pop(BuildContext context, [ result ])
将栈顶路由出栈,result为页面关闭时返回给上一个页面的数据。
Navigator 还有很多其它方法,如Navigator.replace、Navigator.popUntil等,详情请参考API文档或SDK源码注释.
实例方法
Navigator类中第一个参数为context的静态方法都对应一个Navigator的实例方法, 比如Navigator.push(BuildContext context, Route route)等价于Navigator.of(context).push(Route route) route) ,后面介绍的命名路由相关方法也是一样的。
我们在代码中测试一下使用
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Welcome to Flutter',
home: new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center(
child: new RandomWordsWidget(),
),
bottomNavigationBar: new FlatButton(
onPressed: () {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new NewPage();
}));
},
child: Text('跳转到新界面')),
),
);
}
}
class NewPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'New Page',
home: new Scaffold(
appBar: new AppBar(
title: Text('New Page:Title'),
),
body: Text('New Page:Body'),
),
);
}
}
class RandomWordsWidget extends StatefulWidget {
@override
createState() => new RandomWordsStatus();
}
class RandomWordsStatus extends State<RandomWordsWidget> {
@override
Widget build(BuildContext context) {
final wordPair = new WordPair.random();
return new Text(wordPair.asPascalCase);
}
}
我们在界面底部添加了一个导航栏,点击后将会跳转到一个新的界面.运行后,点击,发现没有效果,出现了一个异常:
I/flutter (28564): The following assertion was thrown while handling a gesture:
I/flutter (28564): Navigator operation requested with a context that does not include a Navigator.
I/flutter (28564): The context used to push or pop routes from the Navigator must be that of a widget that is a
I/flutter (28564): descendant of a Navigator widget.
I/flutter (28564): When the exception was thrown, this was the stack:
I/flutter (28564): #0 Navigator.of.<anonymous closure> (package:flutter/src/widgets/navigator.dart:1379:9)
I/flutter (28564): #1 Navigator.of (package:flutter/src/widgets/navigator.dart:1386:6)
I/flutter (28564): #2 Navigator.push (package:flutter/src/widgets/navigator.dart:1011:22)
I/flutter (28564): #3 MyApp.build.<anonymous closure> (package:flutter_demo/main.dart:20:25)
I/flutter (28564): #4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:513:14)
I/flutter (28564): #5 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:568:30)
I/flutter (28564): #6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:120:24)
I/flutter (28564): #7 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
I/flutter (28564): #8 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
I/flutter (28564): #9 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:369:9)
I/flutter (28564): #10 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
I/flutter (28564): #11 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
异常显示,我们使用了一个不包含Navigator的Context来请求Navigator操作,而Navigator进行push或者pop操作时使用的Context必须是Navigator Widget的子类.
从代码中查看,我们使用的Context来自于build方法中,是从StatelessWidget中传递过来的.
具体的分析过程参考博文:
Flutter | 深入理解BuildContext
看过上文后,我们要解决这个问题,必须使用MaterialApp中的context.
我们将首页的代码提取一下,将Scaffold 提取出来,然后使用MaterialApp中的context.
具体代码如下:
import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Welcome to Flutter',
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Welcome to Flutter'),
),
body: new Center(
child: new RandomWordsWidget(),
),
bottomNavigationBar: new FlatButton(
onPressed: () {
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new NewPage();
}));
},
child: Text('跳转到新界面')),
);
}
}
class NewPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'New Page',
home: new Scaffold(
appBar: new AppBar(
title: Text('New Page:Title'),
),
body: Text('New Page:Body'),
),
);
}
}
class RandomWordsWidget extends StatefulWidget {
@override
createState() => new RandomWordsStatus();
}
class RandomWordsStatus extends State<RandomWordsWidget> {
@override
Widget build(BuildContext context) {
final wordPair = new WordPair.random();
return new Text(wordPair.asPascalCase);
}
}
运行测试后完美