在Android中页面跳转使用context.startActivity
,iOS中页面之间跳转使用的是ViewController
。在我们Flutter中,页面之间的跳转与数据传递使用的是Navigator.push
和Navigator.pop
以及Router
。也是比较简单的,我们一起来使用Navigator+Router
看看如何实现下面的效果。
打开新页面并且返回
实现下面效果,打开新页面并且返回到上一级页面。
- 创建两个页面
- Navigator.push(打开页面)
- Navigator.pop(退出当前页面)
新建两个页面
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FirstPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text(" Navigator.push SecondPage"),
onPressed: () {
//导航到SecondPage
_navigateSecondPage(context);
})),
);
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text(" Navigator.push ThirdPage"),
onPressed: () {
//退出当前页面
_backCurrentPage(context);
})),
);
}
}
使用Navigator.push 跳转到新页面
Navigator.push(BuildContext context, Route<T> route)
可以将当前页面转换成Router
,压入由Navigator
管理的路由堆栈(the stack of routes)中。
Route
的具体实现如下:
这里我们使用MaterialPageRoute
void _navigateSecondPage(BuildContext context) {
//MaterialPageRoute({
// @required this.builder,
// RouteSettings settings,
// this.maintainState = true,
// bool fullscreenDialog = false,
// })
Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage();
}));
}
使用Navigator.pop退出当前页面
Navigator.pop(BuildContext context, [ T result ])
,会将当前页面对应的Router
从Navigator
管理的路由堆栈中移除。
//退出当前页面,返回到上一级页面
void _backCurrentPage(BuildContext context) {
Navigator.pop(context);
}
携带数据到新的页面
发送也就是携带数据到新页面也是十分简单,我们改造下上面的_navigateSecondPage
方法即可。在上面的例子中我们通过return SecondPage()
,可以将数据放入到SecondPage
的构造方法中,这样打开新页面的时候数据就自动带入到了新页面。例如,我们携带String
类型的数据到SecondPage
,可以按照下面的方法来弄。
- 改动
SecondPage
的构造方法
class SecondPage extends StatelessWidget {
final value;
SecondPage({Key key, @required this.value}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text("$value"),
onPressed: () {
_backCurrentPage(context);
})),
);
}
}
- 改动
_navigateSecondPage
方法
void _navigateSecondPage(BuildContext context) {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage(value: '我是FirstPage带来的数据');
}));
}
效果如下:
对于页面之间的跳转除了上面的方法之外,还可以基于命名路由的方式自由跳转,下节再讲。
返回数据到上一级页面
- 将要返回的数据放入到
Navigator.pop
中
//退出当前页面,返回到上一级页面
void _backCurrentPage(BuildContext context) {
print('执行了_backCurrentPage');
///只有执行了这个方法,上级页面才会收到返回的数据
Navigator.pop(context, '我是来自SecondPage的数据');
}
- 使用
Navigator.push+async+await
处理返回的数据
/// async关键字声明该函数内部有代码需要延迟执行
/// 使用await会把延迟运算放入到延迟运算的队列(await)中。
void _navigateSecondPage(BuildContext context) async {
print('执行了_navigateSecondPage');
final result =
await Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage();
}));
print('FirstPage收到数据:$result');
}
可以看到上一级收到了数据,不过前提是调用了Navigator.pop(context, '我是来自SecondPage的数据');
,直接返回上级页面,这种情况下,上级页面是收不到数据的。
完整代码如下:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('FirstPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text("Navigator.push SecondPage"),
onPressed: () {
_navigateSecondPage(context);
})),
);
}
// void _navigateSecondPage(BuildContext context) {
// //MaterialPageRoute({
// // @required this.builder,
// // RouteSettings settings,
// // this.maintainState = true,
// // bool fullscreenDialog = false,
// // })
// Navigator.push(context, MaterialPageRoute(builder: (context) {
// return SecondPage(value: '我是FirstPage带来的数据');
// }));
// }
/// async关键字声明该函数内部有代码需要延迟执行
/// 使用await会把延迟运算放入到延迟运算的队列(await)中。
void _navigateSecondPage(BuildContext context) async {
print('执行了_navigateSecondPage');
final result =
await Navigator.push(context, MaterialPageRoute(builder: (context) {
return SecondPage();
}));
print('FirstPage收到数据:$result');
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text("返回数据到FirstPage"),
onPressed: () {
_backCurrentPage(context);
})),
);
}
}
///退出当前页面,返回到上一级页面
void _backCurrentPage(BuildContext context) {
print('执行了_backCurrentPage');
///只有执行了这个方法,上级页面才会收到返回的数据
Navigator.pop(context, '我是来自SecondPage的数据');
}
基于已命名路由调整
除了上述跳转方式之外,Flutter还支持将路由与页面对应起来。进行已命名路由的跳转。这一部分也是比较容易了解的。
import 'package:flutter/material.dart';
class NamedRouter {
static Map<String, WidgetBuilder> routes;
//初始化App
static Widget initApp() {
return MaterialApp(
initialRoute: '/',
routes: NamedRouter.initRoutes(),
);
}
//初始化路由
static initRoutes() {
routes = {
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen()
};
return routes;
}
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Screen'),
),
body: Center(
child: RaisedButton(
child: Text('Launch screen'),
onPressed: () {
// Navigate to the second screen using a named route
Navigator.pushNamed(context, '/second');
},
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to the first screen by popping the current route
// off the stack
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
//main函数中使用
void main() => runApp(NamedRouter.initApp());
回到开头,看看如何基于上面的知识实战实现豆瓣Top150详情。
代码地址
Flutter 豆瓣客户端,诚心开源
Flutter Container
Flutter SafeArea
Flutter Row Column MainAxisAlignment Expanded
Flutter Image全解析
Flutter 常用按钮总结
Flutter ListView豆瓣电影排行榜
Flutter Card
Flutter Navigator&Router(导航与路由)
OverscrollNotification不起效果引起的Flutter感悟分享
Flutter 上拉抽屉实现
Flutter 豆瓣客户端,诚心开源
Flutter 更改状态栏颜色