一、前言
在Android开发中,界面的跳转使用的Context.startActivity来实现,界面通常指的Activity,如果我们的设计是单Activity+Fragment来实现,界面的跳转就需要使用FragmentManager来完成。这些概念到了Flutter中有了一些变化。
二、路由是什么
我们通常使用“屏”来展示应用的不同页面(界面)。比如应用有一屏展示商品列表,点击Item的时候,跳转到新的一“屏”展示商品的详细信息。
在Flutter中,屏(screen) 和 页面(page) 都叫做 路由(route)。
因此, 在后期的开发中,我们基本都会建一个screen或者page的文件夹,里面文件代表一屏需要展示的界面。当前文件的命名也可以加一个screen或者page的后缀,比如login_page.dart 或 login_screen.dart
所以在后面的界面跳转或者页面跳转都值的是路由的跳转,那么如何从一个‘路由’跳转到一个新的路由呢?
三、使用Navigator来实现路由的的跳转功能
在Flutter中,封装了Navigator来实现界面的跳转功能,接下来了解具体的使用。
3.1 使用Navigator.push()跳转到一个新的路由
push()方法需要传入Route对象,随后将Route对象添加到导航器的堆栈上。这里的Route对象我们可以自己实现,当前前期入门的时候,推荐使用MaterialPageRoute,框架已经实现了和平台原生动画类似的动画切换。
Navigator.push(context,
MaterialPageRoute(builder: (context) => const TestPageTwo()));
当然这里我们可以使用Navigator.of(context).push()方法。完成的效果图如下:
3.2 使用Navigator.pop()回退到上一个路由
Flutter中使用Navigator.pop()方法,将到导航器堆栈上的Route对象移除。
下面在test_page2上添加一个回退功能
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('页面2返回按钮'),
),
3.3 传递数据到新页面
在开发中,进程会遇到需要在跳转新页面的时候传递一些数据的,比如从待办列表页到待办详情页,需要传递待办数据id或者更多的信息。
传递参数有两种方式,框架提供了两种方式:构造函数或者RouteSettings,下面分别介绍这两种方式的使用。
3.3.1 传递数据到新页面-通过构造函数方式传递数据
通过构造函数的方式相对简单,在对应的widget构造函数中添加参数即可,如:
class TestPageTwo extends StatelessWidget {
final ToDo todo;
const TestPageTwo({Key? key,required this.todo}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('界面2'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('界面传递数据:${todo.title},${todo.description}'),
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('页面2返回按钮'),
),
],
),
),
);
}
}
3.3.2 传递数据到新页面-使用RouteSettings的方式传递参数
使用RouteSettings ,在创建MaterialPageRoute时添加setting参数,如下所示:
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
settings: RouteSettings(arguments: ToDo(1, '今日待办', '今日事今日毕')),
builder: (context) => const TestPageTwo()));
},
这里如果使用Navigator.pushNamed()方法可以直接传递参数Navigator.pushNamed(context, ‘routeName’,arguments: ToDo());这里命名路由的方式后续讲。
提取RouteSettings传递过来的参数
class TestPageTwo extends StatelessWidget {
const TestPageTwo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final todo = ModalRoute.of(context)!.settings.arguments as ToDo;
......
}
向新页面传递参数,上述两种方式都合适,根据自己的喜好使用即可。但是如果使用命名路由 后则会使用RouteSettings。Navigator.pushNamed()方法中的arguments也转化为了Routesettings对象。
3.4 从一个页面返回数据
在Android中,有startActivityForResult的方式获取页面返回的参数,在Flutter中则更简单一些。
3.4.1 Navigator.pop()方法中加入返回数据
Navigator.pop(context,'返回数据');
3.4.2 Navigator.push时获取返回数据
Navigator.push返回一个Future,异步操作需要结合async和await关键字,更多的用法需要参考dart的异步操作。
_navigateToSecondPage(BuildContext context) async{
final result = await Navigator.push(
context,
MaterialPageRoute(
settings: RouteSettings(arguments: ToDo(1, '今日待办', '今日事今日毕')),
builder: (context) => const TestPageTwo()));
print('$result');
}
3.5 使用命名路由的方式进行界面跳转
前面界面跳转方式和Android原生的基本一致,Flutter还支持命名路由的方式进行跳转,这样可以减少代码的重复以及文件之间的相互引用关系。
3.5.1 配置命名路由
命名路由的配置需要在MaterialApp中的routes参数中进行配置,如下:
return MaterialApp(
......
routes:{
'secondPage': (context) => const TestPageTwo(),
},
)
平时开发中我们都不会直接在这里进行配置,单独放在一个文件中进行配置,例如在routes.dart文件中添加以下代码:
class Routes {
static const initialRoute = '/';
static const routeSecondPage = '/secondPage';
static final routes = {
initialRoute: (context) => const TestPageOne(),
routeSecondPage: (context) => const TestPageTwo()
};
}
接下来修改MaterialApp:
return MaterialApp(
......
routes: Routes.routes,
initialRoute: Routes.initialRoute,
);
注意
使用 initialRoute 时,需要确保你没有同时定义 home 属性。
3.5.2 使用命名路由
使用命名路由则使用Navigator.pushNamed()方法。
Navigator.pushNamed(context, Routes.routeSecondPage)
3.5.3 传递参数
_navigateToSecondPage(BuildContext context) async {
var param = ToDo(1, '今日待办', '今日事今日毕');
final result = await Navigator.pushNamed(context, Routes.routeSecondPage,
arguments: param);
print('$result');
}
3.5.4 获取参数
class TestPageTwo extends StatelessWidget {
const TestPageTwo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final todo = ModalRoute.of(context)!.settings.arguments as ToDo;
......
}
|