资料来源
在背景放一个按钮,按钮触发事件,打开新的页面
new FloatingActionButton(onPressed: ()=>_onTap()),
new FloatingActionButton(onPressed: _onTap),
触发事件需要函数闭包,与js不同
直接跳转页面NewRoute()
_onTap() {
Navigator.push(context, new MaterialPageRoute(builder: (context)=>new NewRoute()));
}
push(Context,PageRoute)
context不多说,当前上下文
PageRoute
PageRoute
类是一个抽象类,表示占有整个屏幕空间的一个模态路由页面,它还定义了路由构建及切换时过渡动画的相关接口及属性
flutter已经实现了安卓风格的MaterialPageRoute
MaterialPageRoute
- 对于Android,当打开新页面时,新的页面会从屏幕底部滑动到屏幕顶部;当关闭页面时,当前页面会从屏幕顶部滑动到屏幕底部后消失,同时上一个页面会显示到屏幕上。
- 对于iOS,当打开页面时,新的页面会从屏幕右侧边缘一致滑动到屏幕左边,直到新页面全部显示到屏幕上,而上一个页面则会从当前屏幕滑动到屏幕左侧而消失;当关闭页面时,正好相反,当前页面会从屏幕右侧滑出,同时上一个页面会从屏幕左侧滑入。
如果想自定义路由切换动画,可以自己继承PageRoute来实现,我们将在后面介绍动画时,实现一个自定义的路由Widget。
自定义路由 自定义路由切换动画
Navigator
Navigator
是一个路由管理的widget,它通过一个栈来管理一个路由widget集合。通常当前屏幕显示的页面就是栈顶的路由。Navigator
提供了一系列方法来管理路由栈,在此我们只介绍其最常用的两个方法:
Future push(BuildContext context, Route route)
将给定的路由入栈(即打开新的页面),返回值是一个Future
对象,用以接收新路由出栈(即关闭)时的返回数据。
bool pop(BuildContext context, [ result ])
将栈顶路由出栈,result
为页面关闭时返回给上一个页面的数据。
Navigator.push(BuildContext context, Route route)
等价于Navigator.of(context).push(Route route)
Navigator.pop(context)等价于Navigator.of(context).pop()
命名路由
类似于阿里ARoute的路由表,通过一个map,把widget构造器与路由名key关联,打开页面,我们只需要知道名字key就可以知道打开哪个页面
注册路由表
在
MyApp
类的build
方法中找到MaterialApp
,添加routes
属性,代码如下:return new MaterialApp( title: 'Flutter Demo', theme: new ThemeData( primarySwatch: Colors.blue, ), //注册路由表 routes:{ "/detail":(context)=>NewRoute(), } , home: new MyHomePage(title: 'Flutter Demo Home Page'), );
移动应用程序经常管理大量路由,通常可以通过名称来引用它们。路由名称按惯例使用类似路径的结构,例如“/a/b/c”,应用程序的主页路由默认为“/”。
要通过路由名称来打开新路由,可以使用:
Future pushNamed(BuildContext context, String routeName,{Object arguments})
修改触发事件代码
_onTap(BuildContext context) {
Navigator.pushNamed(context, "/detail");
// Navigator.of(context).pushNamed("/detail");
}
一样能达到了效果
路由传递参数
命名路由传递参数
在打开路由的时候,pushNamed()函数第三个可选参数就是
一个完整的传递过程
_onTap() {
// Navigator.pushNamed(context, "/detail");
Navigator.of(context).pushNamed("/detail",arguments: "这是路由传递参数");
}
在新的页面中获取参数
@override
Widget build(BuildContext context) {
var content=ModalRoute.of(context).settings.arguments;
// ...
return Scaffold(
appBar: AppBar(
title: Text("New route"),
),
body: Center(
child: Text("content=$content"),
),
);
}
构造器传递参数
规划参数,在构造器中初始化数据
class NewRoute extends StatelessWidget {
final String content;
NewRoute(this.content);
@override
Widget build(BuildContext context) {
// var content=ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text("New route"),
),
body: Center(
child: Text("content=$content"),
),
);
}
}
然后利用构造器打开路由
_onTap() {
Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>new NewRoute("这是参数")));
}
路由返回数据
前面说到pop()方法可以返回数据给上一个路由
建立一个新的页面关系,
在主页面显示默认参数,点击按钮,打开新的页面,
在新页面点击按钮,返回主页,并传递参数
回到主页,获取参数,并显示出来
主页
class FirstPage extends StatefulWidget {
@override
State<FirstPage> createState() {
// TODO: implement createState
return new FirstPageState();
}
}
class FirstPageState extends State<FirstPage> {
bool _result=false;
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
appBar: new AppBar(
title: new Text("界面1"),
),
body: new Container(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton(onPressed: _onTap),
],
),
Text("$_result"),
],
),
)
);
}
_onTap(){
Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>new MyDialog()));
}
}
次页面
class MyDialog extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Dialog"),
),
body: Center(
child: GestureDetector(
child: Text("确认"),
onTap: (){
// Navigator.of(context).pop(true);
},
),
),
);
}
}
返回数据
在次页面中,onTap方法,调用pop()返回true
onTap: (){
Navigator.of(context).pop(true);
},
获取数据
这里如果需要获取数据,就需要改动主页的_onTap方法
_onTap() async {
bool value= await Navigator.of(context).push(MaterialPageRoute(builder: (context)=>MyDialog()));
setState(() {
_result=value;
});
}
因为value的赋值需要等待次页面返回才能获取赋值,所以,需要用await关键字标记,对应的,方法就需要用async关键字标记这是个方法
value赋值后,调用setState()方法,刷新页面中的_result
模拟Fragment/Dialog
更多Flutter和安卓的比较,参考文档
待续