300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Flutter Navigator基础使用

Flutter Navigator基础使用

时间:2021-05-21 16:40:33

相关推荐

Flutter Navigator基础使用

Navigator的使用分为两部分:

本节说一些基本操作,如果你已经掌握了Navigator的基本跳转姿势,请移步Flutter Navigator品如用法

1.路由最基本的使用-跳转和退出

大多数App都包含了许多页面用来呈现不同种类的信息。例如:一个app可能存在“商品列表页”,当点击item的时候又会跳转到对应“商品详情”页面。

在Flutter中,页面被称之为route(路由)。在android中路由等同于Activity,ios中路由等同于ViewController,然后在Flutter中路由只是一个widget。

两个路由之间的跳转需要经历下面三个步骤

创建两个routeNavigate到第二个route使用Navigator.push()返回到第一个route使用Navigator.pop()

1.1创建两个路由

首先创建两个页面,由于这只是为了演示最基本的导航功能,所以每个页面只包含一个按钮。点击第一个页面的按钮跳转到第二个页面,点击第二个页面的按钮返回到第一个页面

class FirstRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('First Route'),),body: Center(child: RaisedButton(child: Text('Open route'),onPressed: () {// 点击跳转到第二个route},),),);}}class SecondRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Second Route"),),body: Center(child: RaisedButton(onPressed: () {// 点击回到第一个route},child: Text('Go back!'),),),);}}

1.2.使用Navigator.push()来跳转页面

我们使用Navigator.push()来切换页面。这个方法会调价一个新的Route到route栈中,而这个栈是由Navigator来管理的。那么路由栈是从何而来呢?你可以船舰你自己的路由栈,或者直接使用系统提供的MaterialPageRoute。这个组件可以很方便的实现路由跳转动画。

在FirstRoute组件中的onPress方法中,添加相应的跳转代码

onPressed: () {Navigator.push(context,MaterialPageRoute(builder: (context) => SecondRoute()),);}

1.3.使用Navigator.pop()来返回上一个页面

我们使用Navigator.pop()来退出SecondRoute并回到FirstRoute,pop()方法回将当前路由从Route栈中移除

在SecondRoute组件中的onPress方法中,添加相应的返回代码

onPressed: () {Navigator.pop(context);}

完整的代码如下:

import 'package:flutter/material.dart';void main() {runApp(MaterialApp(title: 'Navigation Basics',home: FirstRoute(),));}class FirstRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('First Route'),),body: Center(child: RaisedButton(child: Text('Open route'),onPressed: () {Navigator.push(context,MaterialPageRoute(builder: (context) => SecondRoute()),);},),),);}}class SecondRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Second Route"),),body: Center(child: RaisedButton(onPressed: () {Navigator.pop(context);},child: Text('Go back!'),),),);}}

2.通过Named Routes(路由表)来做跳转

在第一节中我们学会了如何使用Navigator来做跳转和退出。然而如果我们的项目中出现了多次跳转到同一个页面的情况,这种方式会造成大量代码的重复。解决方案就是使用Named Route。

为了使用Named Routes,我们要使用Navigator.pushNamed()函数,我们还是引用第一节的例子,只是步骤上有细微的差别。

创建两个route定义创建的route跳转到SecondRoute使用Navigator.pushNamed()返回到第一个页面使用Navigator.pop()

2.1.创建两个Route

和第一节中的代码一模一样,这里不在赘述

2.2.定义创建的route

我们需要在MaterialApp的构造方法中添加两个额外的属性:initialRouteroutes

initialRoutes表示起始的route(可以理解为app打开后显示的第一个页面),routes表示除开initialRoute外的所有route。具体代码如下

MaterialApp(// 定义APP启动时第一个显示的页面,在本例中,initialRoute指代FirstScreeninitialRoute: '/',routes: {// 当navigating到‘/’ route时,构建FirstScreen widget'/': (context) => FirstScreen(),// 当navigating 到"/second" route, 构建SecondScreen widget.'/second': (context) => SecondScreen(),},);

可以看出使用Named Routes的时候只是给每个Route定义了一个别名,这样我们就可以根据这个别名来进行跳转了

2.3.Navigate到SecondScreen

使用Navigator.pushNamed()来跳转,当这个方法被调用的时候,Flutter会去定义的routes中转到别名所对应的route,并进行跳转

onPressed: () {// 跳转到SecondScreenNavigator.pushNamed(context, '/second');}

2.4退出页面

使用Navigator.pop()

onPressed: () {// 从第二个页面返回Navigator.pop(context);}

完整的代码如下:

import 'package:flutter/material.dart';void main() {runApp(MaterialApp(title: 'Named Routes Demo',initialRoute: '/',routes: {'/': (context) => FirstScreen(),'/second': (context) => SecondScreen(),},));}class FirstScreen extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('First Screen'),),body: Center(child: RaisedButton(child: Text('Launch screen'),onPressed: () {Navigator.pushNamed(context, '/second');},),),);}}class SecondScreen extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("Second Screen"),),body: Center(child: RaisedButton(onPressed: () {Navigator.pop(context);},child: Text('Go back!'),),),);}}

3.在Named Route中传值

前面两节只是说了如何跳转和退出,但是在实际项目开发中肯定是少不了页面之间数据交互的问题。

Navigator.pushNamed()并不是一个空参函数,一下是该方法的源码

@optionalTypeArgsstatic Future<T> pushNamed<T extends Object>(BuildContext context,//路由路径String routeName, {//携带的参数Object arguments,}) {return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);}

arguments是跳转携带的参数,它是一个Object,意味着可以传递任意类型的参数,但是跳转到下一个页面后如何把这个值取出来呢,貌似没有相应的“key”呢。下面介绍完整的传值和取值步骤

准备好你要传递的数据创建一个页面来获取传递的数据在routes表中注册这个页面跳转

3.1.准备传递的数据

首先,我们定义好要传递的数据。这里我们传递两个参数,title和message,并将它们封装到一个Bean中

class ScreenArguments {final String title;final String message;ScreenArguments(this.title, this.message);}

3.2.创建一个页面来接受传递的数据

创建一个新的页面来接受传递的参数并显示。至于我们上面提到的如何来获取arguments,我们使用ModalRoute.of()就可以啦。这个方法3可以拿到当前路由携带的参数。

class ExtractArgumentsScreen extends StatelessWidget {static const routeName = '/extractArguments';@overrideWidget build(BuildContext context) {//获取传递的参数final ScreenArguments args = ModalRoute.of(context).settings.arguments;return Scaffold(appBar: AppBar(title: Text(args.title),),body: Center(child: Text(args.message),),);}}

3.3.注册新的页面

当然啦,使用pushNamed跳转肯定要在routes表中注册该页面,所以把ExtractArgumentsScreen注册进去

MaterialApp(routes: {ExtractArgumentsScreen.routeName: (context) => ExtractArgumentsScreen(),},);

3.4跳转

一切准备就绪,我们使用pushNamed来实现跳转,并将准备好的参数传递过去

RaisedButton(child: Text("使用pushNamed携带参数跳转"),onPressed: () {//点击事件,触发跳转Navigator.pushNamed(context,ExtractArgumentsScreen.routeName,arguments: ScreenArguments('我是被传递的title','我是被传递的message.',),);},);

引申:从3.2节我们得知ModalRoute.of()可以获取传递过来的参数,但是我们的例子中是使用的pushNamed传递的参数,如果使用Navigator.push()传递参数能获取到嘛?例如这样:

Navigator.push(context,MaterialPageRoute(builder: (context) => ExtractArgumentsScreen(),settings: RouteSettings(arguments: ScreenArguments('我是title','我是message.',),),),);

先给出答案:这两种方式传值都可以用ModalRoute.of()来取值,因为这两种跳转方式最终都会调用Future<T> push<T extends Object>(Route<T> route),有兴趣的可以去查看源码,这里不多赘述了。

3.5.跳转的另外一种方式

除了我们以上所说的跳转方式,我们也可以使用onGenerateRoute来进行跳转传值。

在本例中我们传递的值依然是title和message,并且封装成一个ScreenArguments实体类,接受参数的页面需要增加一个构造方法来接收这两个值

class PassArgumentsScreen extends StatelessWidget {static const routeName = '/passArguments';final String title;final String message;//定义一个构造方法const PassArgumentsScreen({Key key,@required this.title,@required this.message,}) : super(key: key);@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text(title),),body: Center(child: Text(message),),);}}

在MaterialApp中添加onGnerateRoute属性

MaterialApp(onGenerateRoute: (settings) {// 判断当前route,分别进行处理if (settings.name == PassArgumentsScreen.routeName) {// 将settings.arguments转换为正确的类型 ScreenArguments.final ScreenArguments args = settings.arguments;//通过构造方法传值return MaterialPageRoute(builder: (context) {return PassArgumentsScreen(title: args.title,message: args.message,);},);}},);

然后再来看一下使用onGenerateRoute方式做跳转的代码

Navigator.push(context,MaterialPageRoute(builder: (context) => ExtractArgumentsScreen(),settings: RouteSettings(arguments: ScreenArguments('我是title','我是message.',),),),);

4.携带参数退出

我们已经学习了如何跳转,退出,携带参数跳转,接收传递的参数。但是当一个页面退出的时候如何携带参数呢?例如我们打开了一个联系人选择页面,点击一个item后页面退出,我们需要知道选择的联系人信息是什么。

在前面我们说到退出页面只需要调用Navigator.pop(context)就行了,实际上这个方法还有一个可选参数,一起来看下完整的代码

@optionalTypeArgsstatic bool pop<T extends Object>(BuildContext context, [ T result ]) {return Navigator.of(context).pop<T>(result);}

这里的第二个参数T就是退出页面时携带的参数,下面我们来详细看一下Navigator.pop()的用法

创建一个页面,名叫HomeScreen并添加一个按钮跳转到SelectionScreen创建SelectionScreen,这个页面包含两个按钮,点击后的效果都是退出页面并携带不同的返回值在HomeScreen中接收返回值,并用一个Snackbar显示

4.1创建一个页面,名叫HomeScreen并添加一个按钮跳转到SelectionScreen

class SelectionButton extends StatelessWidget {@overrideWidget build(BuildContext context) {return RaisedButton(onPressed: () {_navigateAndDisplaySelection(context);},child: Text('Pick an option, any option!'),);}//点击跳转到SelectionScreen并接收返回值_navigateAndDisplaySelection(BuildContext context) async {// Navigator.push returns a Future that completes after calling// Navigator.pop on the Selection Screen.//调用Navigator.push()会返回一个Furture,根据这个Future可以接收页面返回的参数,这个下面再讲final result = await Navigator.push(context,// Create the SelectionScreen in the next step.MaterialPageRoute(builder: (context) => SelectionScreen()),);}}

4.2创建SelectionScreen,这个页面包含两个按钮,点击后的效果都是退出页面并携带不同的返回值

class SelectionScreen extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('Pick an option'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Padding(padding: const EdgeInsets.all(8.0),child: RaisedButton(onPressed: () {// 退出页面,并携带一个返回值‘Yep!' Navigator.pop(context, 'Yep!');},child: Text('Yep!'),),),Padding(padding: const EdgeInsets.all(8.0),child: RaisedButton(onPressed: () {// 退出页面,并携带一个返回值 "Nope"Navigator.pop(context, 'Nope!');},child: Text('Nope.'),),)],),),);}}

4.3在HomeScreen中接收返回值,并用一个Snackbar显示

_navigateAndDisplaySelection(BuildContext context) async {final result = await Navigator.push(context,MaterialPageRoute(builder: (context) => SelectionScreen()),);String value = result as String;Scaffold.of(context)..removeCurrentSnackBar()..showSnackBar(SnackBar(content: Text("$value")));}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。