本文首发于公众号「刘望舒」
ReactNative入门系列
React Native组件
Flutter基础系列
在Android开发中我们使用Intent来进行页面跳转,也称之为原生路由,后来出现了一些路由框架,比如ARouter。
在Flutter中进行界面跳转的就是路由,路由用Route类来进行表示,Navigator是对Route进行管理的Widget。这一篇文章我们来学习路由和数据传递。flutter路由的使用方式主要有两种,一种是新建路由,一种是注册路由。
创建两个页面,第一个页面有一个按钮,点击这个按钮跳到第二个页面。先来实现第一个页面:
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一页"),
),
body: Center(
child: RaisedButton(
child: Text("跳转到第二页"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(), maintainState: false));
},
),
),
);
}
}
通过Navigator.push()方法将一个Route对象添加到Navigator管理的Route堆栈中,这里的Route对象是一个MaterialPageRoute,它自带页面切换动画,并且适配了Android和iOS,如果是Android,页面进入动画是向上滑动并淡出,退出是相反的;如果是iOS,页面进入动画是从右侧滑入,退出同样是相反的。一般来说使用MaterialPageRoute就够用了,如果不满足需求,可以实现自定义Route。
接着来实现第二个页面,代码如下所示。
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二页"),
),
body: Center(
child: RaisedButton(
child: Text("返回到第二页"),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
Navigator.pop()方法用于关闭当前页面,返回上一个页面,并将当前的Route对象从Navigator管理的Route 堆中移除。
完整的代码如下所示。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一页"),
),
body: Center(
child: RaisedButton(
child: Text("跳转到第二页"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
maintainState: false,
),
);
},
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二页"),
),
body: Center(
child: RaisedButton(
child: Text("返回到第二页"),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
如果很多页面都跳转到了同一个页面,每次都要新建路由,那么会写很多重复的代码,使用注册路由就可以简化。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
initialRoute: '/First',//1
routes: {
'/First': (context) => FirstPage(),
"/Second": (context) => SecondPage()
},
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一页"),
),
body: Center(
child: RaisedButton(
child: Text("跳转到第二页"),
onPressed: () {
Navigator.pushNamed(context, '/Second');//2
},
),
),
);
}
}
...
省略了第二页的代码,因为没有什么变化。改变的是我们需要定义路由表,路由表的格式为Map
其中key为路由名称,value是builder回调函数,用于生成相应的路由Widget。通过路由名称入栈新路由时,应用会根据路由名称在路由表中找到对应的WidgetBuilder回调函数,通过调用该回调函数生成路由widget并返回。
注释1处用来定义初始路由的页面,接着注册路由表,里面包含了两个页面,分别是FirstPage和SecondPage。
注释2处通过路由名称来打开SecondPage。
页面跳转的时候经常需要传递数据,一般有两种情况,一种是页面跳转数据传递,另一种是页面跳转返回数据,这里分别来进行介绍。
一个页面跳转到一个新的页面数据传递的方式主要有以下两种:
一般来说会使用第一种方式,下面来进行举例。
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一页"),
),
body: Center(
child: RaisedButton(
child: Text("跳转到第二页"),
onPressed: () {
Navigator.pushNamed(context, '/Second',arguments: CustomArgumnets('Android进阶之光'));
},
),
),
);
}
}
class CustomArgumnets {
String content;
PassArgumnets(this.content);
}
我们通过arguments属性来传递参数,这里自定义了一个CustomArgumnets,用来传递参数。
改写第一小节SecondPage的代码用来获取数据,如下所示。
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CustomArgumnets customArgumnets =ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text("第二页"),
),
body: Center(
child: Column(
children: <Widget>[
Text('第一页的数据为:'),
Text(customArgumnets.content),
RaisedButton(
onPressed: () {
Navigator.pop(context);//1
},
child: Text('返回第一页'),
),
],
),
),
);
}
}
除了页面跳转需要传递数据,有时还需要从第二个页面返回数据,改写3.1小节的SecondPage注释1处的代码。
Navigator.pop(context,CustomArgumnets('Android进阶解密'));
接着改写FirstPage,如下所示。
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一页"),
),
body: Center(
child: RaisedButton(
child: Text("跳转到第二页"),
onPressed: () {
_navigateToSecondPage(context);
},
),
),
);
}
_navigateToSecondPage(BuildContext context) async {
dynamic customArgumnets = await Navigator.pushNamed(context, '/Second',
arguments: CustomArgumnets('Android进阶之光'));//1
print(customArgumnets.content);
}
}
注释1处的代码可以接java收返回的结果,并且使用异步来防止阻塞UI。最后贴上完整的代码。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter",
initialRoute: '/First',
routes: {
'/First': (context) => FirstPage(),
"/Second": (context) => SecondPage()
},
home: FirstPage(),
);
}
}
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第一页"),
),
body: Center(
child: RaisedButton(
child: Text("跳转到第二页"),
onPressed: () {
_navigateToSecondPage(context);
},
),
),
);
}
_navigateToSecondPage(BuildContext context) async {
dynamic customArgumnets = await Navigator.pushNamed(context, '/Second',
arguments: CustomArgumnets('Android进阶之光'));
print(customArgumnets.content);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CustomArgumnets customArgumnets =ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text("第二页"),
),
body: Center(
child: Column(
children: <Widget>[
Text('第一页的数据为:'),
Text(customArgumnets.content),
RaisedButton(
onPressed: () {
Navigator.pop(context,CustomArgumnets('Android进阶解密'));
},
child: Text('返回第一页'),
),
],
),
),
);
}
}
class CustomArgumnets {
String content;
CustomArgumnets(this.content);
}
运行程序,当我们点击返回第一页,在控制台中会打印出 Android进阶解密。
Flutter基础系列
Flutter基础(一)移动开发的跨平台技术演进
Flutter基础(二)Flutter开发环境搭建和Hello World
Flutter基础(三)Dart快速入门
Flutter基础(四)开发Flutter应用前需要掌握的Basic Widget
Flutter基础(五)Material组件之MaterialApp、Scaffold、AppBar
Flutter基础(六)Material组件之BottomNavigationBar、TabBar、Drawer
Flutter基础(七)Scrolling Widget之ListView、GridView、PageView
Flutter基础(八)手势相关Widget:GestureDetector和Dismissible
Flutter基础(九)资源和图片
Flutter基础(十)布局Widget快速入门
Flutter基础(十一)网络请求(Dio)与JSON数据解析
Flutter基础(十二)路由(页面跳转)与数据传递
Flutter基础(十三)Flutter与Android的相互通信