基本路由
navigator.push 的定义如下:
@optionalTypeArgs
static Future<T> push<T extends Object>(BuildContext context, Route<T> route) {
return Navigator.of(context).push(route);
}
可以看出,方法接收两个参数,一个是上下文context
,基本原样给,不用深究。另外一个是 Route Widget
,但是 Route
是一个抽象类,因此在实际使用中,我们不会直接传入Route
,而是会使用MaterialPageRoute
MaterialPageRoute({
@required this.builder,
RouteSettings settings,
this.maintainState = true,
bool fullscreenDialog = false,
})
核心是提供一个builder
函数,比如像下面这样:
// 跳转到Page2页面
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Page2()),
);
navigator.pop 的定义如下:
@optionalTypeArgs
static bool pop<T extends Object>(BuildContext context, [ T result ]) {
return Navigator.of(context).pop<T>(result);
}
使用的例子:
onPressed: () {
Navigator.pop(context);
},
点击导航栏的返回图标,这个函数就会被默认执行,不需要自己写。
传值
MaterialPageRoute
的构造参数中的 RouteSettings: settings
这个参数就是路由的基本信息,它的arguments
可以用来存储路由相关的参数字段。
const RouteSettings({
this.name,
this.isInitialRoute = false,
this.arguments,
});
下面是一个使用的例子
Navigator.of(context).push(
new MaterialPageRoute(
builder: (context) {
return NewRouteWidget();
},
settings: RouteSettings(
arguments: {'name': 'postbird'},
), // 传参
fullscreenDialog: true,
),
);
目标页面,可以通过ModalRoute
获得传过来的参数:
/// Creates a route that blocks interaction with previous routes.
ModalRoute({
RouteSettings settings,
}) : super(settings: settings);
一个例子如下:
// 新路由页面
class NewRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
Map args = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(title: Text('获取参数')),
body: Center(
child: Column(
children: <Widget>[
// 这里会显示传递过来的参数:{'name': 'postbird'}
Text(args.toString()),
],
)));
}
}
回传参数
navigator.push
的返回值是一个Future
,所以可以使用async/await
得到返回值。
onPressed: () async {
try {
final value = await Navigator.of(context).pushNamed('/page2');
print("收到回传的数据:$value");
} catch (e) {
print("异常:$e");
}
},
navigator.pop
可以带参数。比如:
onPressed: (){
Navigator.of(context).pop("这是回传的数据");
}
命名路由
- 提供一个路由表,这是一个
Map
,是字符串和WidgetBuilder
的对应关系。比如:
/// 路由表
final Map<String, WidgetBuilder> routeTable = {
'/' : (content) => Home(),
'/page1' : (content) => Page1(),
'/page2' : (content) => Page2(),
'/page3' : (content) => Page3(),
};
- 把这个路由表放在
MaterialApp
的routes
参数中
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: routeTable,
);
}
}
使用的例子如下,比如跳转到Page1
页面:
onPressed: (){
Navigator.of(context).pushNamed('/page1');
}
小结
-
命名路由使用起来比较简单,只要通过字符串来区分不同的页面就可以了,所有的
WidgetBuilder
都集中在一个地方。 -
命名路由的起点页面不需要导入目标页面,不需要知道目标页面的
WidgetBuilder
。只需要知道路由表中的“名字”就可以了,实现了解耦。 -
命名路由不能向目标页面传递参数,这个很不方便。基本路由虽然有耦合,使用也相对麻烦,不过可以传递参数。
-
命名路由和基本路由都可以拿到回传的值,方法是一样的。
pushName
也是调用push
实现的,两种都返回一个Future
,使用异步的方式就可以拿到返回值。
@optionalTypeArgs
Future<T> pushNamed<T extends Object>(
String routeName, {
Object arguments,
}) {
return push<T>(_routeNamed<T>(routeName, arguments: arguments));
}
onGenerateRoute 路由拦截
能否把命名路由和组合路由的优点结合起来呢。方法就是在MaterialApp
的onGenerateRoute
参数中提供一个Route
的动态生成函数。
import 'package:flutter/material.dart';
import './page/home.dart';
import './page/page1.dart';
import './page/page2.dart';
import './page/page3.dart';
/// 路由表
final Map<String, WidgetBuilder> routeTable = {
'/' : (content) => Home(),
'/page1' : (content) => Page1(),
'/page2' : (content) => Page2(),
'/page3' : (content) => Page3(),
};
// 动态生成路由
final onGenerateRoute = (RouteSettings settings) {
// 从路由表得到builder
final name = settings.name;
var builder = routeTable[name];
// 如果路由表中未定义,跳转到未定义路由页面
if (builder == null) {
builder = (content) => NotFoundPage();
}
// 构建动态的route
final route = MaterialPageRoute(
builder: builder,
settings: settings,
);
return route;
};
- route.dart
- MaterialPageRoute需要的WidgetBuilder来自路由表
- MaterialPageRoute的参数来自调用者。
- 这个形式上是命名路由,但是本质上却是基本路由(也叫动态路由),所以能够传递参数。因此,
MaterialApp
的routes
参数不能提供(否则就是命名路由,不能传参),而是提供onGenerateRoute
参数。
import 'package:flutter/material.dart';
import './route.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
onGenerateRoute: onGenerateRoute,
);
}
}
main.dart
- 使用的方式和命名路由一样。
Navigator.of(context).pushNamed('/page1');
不传参数,适合大多数情况
Navigator.of(context).pushNamed('/page3', arguments: {
"title": "透传title",
"name": 'postbird',
'password': '123456'
});
传递参数,有些时候需要
- 获取参数的方法仍然使用
ModalRoute.of(context).settings.arguments
这是Flutter
内部提供的机制,直接用就行。
import 'package:flutter/material.dart';
class Page3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
final arguments = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar:AppBar(
title: Text("页面3"),
) ,
body: Center(
child : Text("页面3内容区域${arguments != null ? arguments : ''}"),
) ,
);
}
}
Demo路径
参考文章
flutter小记之路由和导航
Flutter进阶:路由、路由栈详解及案例分析
flutter中的命名路由
Flutter 路由导航、路由传值、ModalRoute
Flutter 命名路由、路由组、路由替换、路由销毁
网友评论