Navigator
路由(Route)在移动开发中通常指页面。路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。在Flutter中,不同页面之间进行切换和发送数据,这些页面被称为Route(路由),是由一个Navigator的widget进行管理。Flutter中的路由管理和原生开发类似,导航管理都会维护一个栈,入栈(push)操作对应打开一个新页面,出栈(pop)操作对应页面关闭操作,而路由管理主要是指如何来管理路由栈。
Navigator
常用方法
- push 将设置的router信息推送到Navigator上,实现页面跳转。
- of 主要是获取 Navigator最近实例的好状态。
- pop 返回到上个页面。
关闭两个页面后跳转到 settings 页面
Navigator.of(context)
..pop()
..pop()
..pushNamed('/settings');
- canPop 判断是否可以导航到新页面
- maybePop 可以理解为canPop的升级版,maybePop则对此进行了升级——如果可以pop则直接pop,否则什么都不做。
- popAndPushNamed 指将当前页面pop,然后跳转到制定页面
- popUntil 反复执行pop ,直到返回到我们指定的页面为止
- pushAndRemoveUntil 跳转到新的页面,并删除先前的所有路由,常用于退出登录后返回登录页面,这时候关闭登录页面就直接退出App。
- pushNamedAndRemoveUntil 同上,不过这里是使用命名路由
- pushReplacement 路由替换。
- pushReplacementNamed 同上,不过这里是使用命名路由
- removeRoute 从Navigator中删除路由,同时执行Route.dispose操作。
- removeRouteBelow 从Navigator中删除路由,同时执行Route.dispose操作,要替换的路由是传入参数anchorRouter里面的路由。
- replace 将Navigator中的路由替换成一个新路由。
- replaceRouteBelow 将Navigator中的路由替换成一个新路由,要替换的路由是是传入参数anchorRouter里面的路由。
**
flutter中的默认导航分成两种,一种是命名的路由,一种是构建路由。
**
构建路由
直接调用Navigator的构建方法进行界面跳转的方式叫构建路由
Push到下一个界面(不带参数),并接收返回数据
Navigator.push 的返回值为Future, 所以可以用then接收数据
import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';
void main() => runApp(new MaterialApp(home: new MyApp()));
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('首页'),
),
body: new Center(
child: new RaisedButton(
onPressed: () {
//界面跳转方法push
Navigator.push<String>(context,
new MaterialPageRoute(builder: (BuildContext context) {
return new SecondPage();
})).then((String result) {
//接收并打印返回界面的参数
print(result);
});
},
child: Text('跳转'),
),
),
//bottomNavigationBar: new BottomNavigationWidget(),
);
}
}
Pop回上一个界面并返回参数
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('SecondPage'),
),
body: SafeArea(
child: RaisedButton(
child: Text("返回"),
onPressed: () {
//退出当前页面,并返回参数
Navigator.pop(context, "我胡汉三回来了");
})),
);
}
}
push下个界面(带参数)
import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';
void main() => runApp(new MaterialApp(home: new MyApp()));
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('首页'),
),
body: new Center(
child: new RaisedButton(
onPressed: () {
//界面跳转
Navigator.push<String>(context,
new MaterialPageRoute(builder: (BuildContext context) {
return new SecondPage(s: '子界面');
})).then((String result) {
//接收并打印返回界面的参数
print(result);
});
},
child: Text('跳转'),
),
),
);
}
}
第二个界面
import 'package:flutter/material.dart';
class SecondPage extends StatelessWidget {
final s;
// SecondPage(this.s);
SecondPage({Key key, @required this.s}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("$s"),
),
body: SafeArea(
child: RaisedButton(
child: Text("返回"),
onPressed: () {
//退出当前页面,并返回参数
Navigator.pop(context, "我胡汉三回来了");
})),
);
}
}
命名路由
将应用中需要访问的每个页面命名为不重复的字符串,通过这些字符串来导航到具体页面的方式叫命名路由。一般在app中使用的都是命名路由方式,进行路由管理。
简单使用
import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';
void main() => runApp(new MaterialApp(
home: new MyApp(),
///注册路由
routes: {
///SecondPage界面的路由地址
'second_page': (context) => SecondPage(s: '路由界面'),
},
));
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('首页'),
),
body: new Center(
child: new RaisedButton(
onPressed: () {
//界面跳转
Navigator.pushNamed(context, 'second_page');
},
child: Text('跳转'),
),
),
//bottomNavigationBar: new BottomNavigationWidget(),
);
}
}
SecondPage类 内容同上!
界面跳转传参
import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';
void main() => runApp(new MaterialApp(
home: new MyApp(),
///注册路由
routes: {
///SecondPage界面的路由地址
'second_page': (context) => SecondPage(s: '路由界面'),
},
));
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('首页'),
),
body: new Center(
child: new RaisedButton(
onPressed: () {
//界面跳转
Navigator.of(context)
.pushNamed('second_page', arguments: '传参数界面')
.then((msg) {//接收下级界面返回参数
print(msg);
});
},
child: Text('跳转'),
),
),
);
}
}
//SecondPage界面
import 'package:flutter/material.dart';
class SecondPage extends StatelessWidget {
final s;
SecondPage({Key key, @required this.s}) : super(key: key);
@override
Widget build(BuildContext context) {
//取出路由参数
String msg = ModalRoute.of(context).settings.arguments as String;
return Scaffold(
appBar: AppBar(
title: Text("$s"),
),
body: SafeArea(
child: RaisedButton(
child: Text('$msg'),
onPressed: () {
//退出当前页面,并返回参数
Navigator.pop(context, "我胡汉三回来了");
})),
);
}
}
命名路由封装
创建路由管理类(app_routes.dart)
import 'package:flutter/material.dart';
import 'package:exercise/secondPage.dart';
import 'package:exercise/threePage.dart';
final String secondPage = '/SecondPage';
final String threePage = '/ThreePage';
// 配置路由表
final routes = {
secondPage: (context) => SecondPage(),
threePage: (context) => ThreePage(),
};
class UnknownPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('跳转错误'),
centerTitle: true,
),
);
}
}
// 路由拦截(固定写法)
Route onGenerateRoute(RouteSettings settings) {
final String name = settings.name;
final Function pageBuilder = routes[name];
if (pageBuilder != null) {
if (settings.arguments != null) {
// 如果透传了参数
return MaterialPageRoute(
builder: (context) =>
pageBuilder(context, arguments: settings.arguments));
} else {
// 没有透传参数
return MaterialPageRoute(builder: (context) => pageBuilder(context));
}
}
return MaterialPageRoute(builder: (context) => UnknownPage());
}
//首先从路由表中拿到路由的 builder,如果能够拿到 builder,则判断是否存在 RouteSettings,如果存在则直接通关构造函数的 arguments 传递给页面 Page Widget。
//这种条件就允许页面 Widget 构造函数中,必须有 arguments 这个参数才可以,比如 /sign 代码如下:
//这样的优点在于不需要通过 ModalRoute.of(context).settings.xxx 拿数据。直接映射到 Widget 中
初始化路由并跳转子界面,不传参数(main.dart)
import 'package:flutter/material.dart';
import 'package:exercise/app_routes.dart';
void main() => runApp(
new MaterialApp(
home: new MyApp(),
//注册路由
routes: routes,
onGenerateRoute: onGenerateRoute,
//路由错误页面
onUnknownRoute: (RouteSettings setting) =>
MaterialPageRoute(builder: (context) => UnknownPage()),
),
);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('首页'),
),
body: new Center(
child: new RaisedButton(
onPressed: () {
//界面跳转( 无参数)
Navigator.pushNamed(context, secondPage).then((msg) {
print(msg);
});
},
child: Text('跳转'),
),
),
//bottomNavigationBar: new BottomNavigationWidget(),
);
}
}
初始化路由并跳转子界面,传参数并返回值给父试图(secondPage.dart)
import 'package:flutter/material.dart';
import 'package:exercise/app_routes.dart' as mRoutes;
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("按钮"),
),
body: SafeArea(
child: Column(
children: <Widget>[
new RaisedButton(
child: Text('返回'),
onPressed: () {
//退出当前页面,并返回参数
Navigator.pop(context, "我胡汉三回来了");
}),
new RaisedButton(
child: Text('下一个界面'),
onPressed: () {
//跳转子界面,传值参数
Navigator.pushNamed(context, mRoutes.threePage,
arguments: '我是谁');
})
],
)),
);
}
}
接收父界面传递参数(threePage.dart)
import 'package:flutter/material.dart';
class ThreePage extends StatelessWidget {
//final s;
//ThreePage({Key key, @required this.s}) : super(key: key);
@override
Widget build(BuildContext context) {
//取出父界面路由参数
String msg = ModalRoute.of(context).settings.arguments as String;
return Scaffold(
appBar: AppBar(
title: Text('界面三'),
),
body: SafeArea(
child: RaisedButton(
child: Text('$msg'),
onPressed: () {
//退出当前页面,并返回参数
Navigator.pop(context);
})),
);
}
}
遇到的坑
解决方式