1. 路由管理
1.1. 一个简单示例
- 创建一个新路由,命名“NewRoute”。
class NewRoute extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("New route"), ), body: Center( child: Text("This is new route"), ), ); } }
- 我们添加了一个打开新路由的按钮,点击该按钮后就会打开新的路由页面。
Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ... //省略无关代码 TextButton( child: Text("open new route"), onPressed: () { //导航到新路由 Navigator.push( context, MaterialPageRoute(builder: (context) { return NewRoute(); }), ); }, ), ], )
1.2. MaterialPageRoute
MaterialPageRoute继承自PageRoute类,PageRoute类是一个抽象类,表示占有整个屏幕空间的一个模态路由页面。
MaterialPageRoute 是 Material组件库提供的组件,它可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画。
MaterialPageRoute 构造函数的各个参数的意义:
MaterialPageRoute({
WidgetBuilder builder,
RouteSettings settings,
bool maintainState = true,
bool fullscreenDialog = false,
})
- builder:是一个回调函数,返回值是一个widget,也就是我们跳转的页面。
- settings:包含路由的配置信息,如路由名称、是否初始路由(首页)。
- maintainState:一个已经不可见(被上面的盖住完全看不到啦~)的组件,是否还需要保存状态。
- fullscreenDialog:表示新的路由页面是否是一个全屏的模态对话框。
1.3. Navigator
Navigator是一个路由管理的组件,它提供了打开和退出路由页方法。
- Future push(BuildContext context, Route route) 将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据。
- bool pop(BuildContext context, [ result ]) 将栈顶路由出栈,result 为页面关闭时返回给上一个页面的数据。
- 实例方法 Navigator.push(BuildContext context, Route route)等价于Navigator.of(context).push(Route route)。
1.4. 路由传值
传值:
Navigator.pop(context, "我是返回值")
获取值:
() async {
// 打开`TipRoute`,并等待返回结果
var result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return TipRoute(
// 路由参数
text: "我是提示xxxx",
);
},
),
);
//输出`TipRoute`路由返回结果
print("路由返回值: $result");
}
1.5. 命名路由
1.5.1. 1. 路由表
它是一个Map,key为路由的名字,是个字符串;value是个builder回调函数,用于生成相应的路由widget。
Map<String, WidgetBuilder> routes;
1.5.2. 2. 注册路由表
MaterialApp添加routes属性:
MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
//注册路由表
routes:{
"new_page":(context) => NewRoute(),
... // 省略其他路由注册信息
} ,
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
将home注册为命名路由:
MaterialApp(
title: 'Flutter Demo',
initialRoute:"/", //名为"/"的路由作为应用的home(首页)
theme: ThemeData(
primarySwatch: Colors.blue,
),
//注册路由表
routes:{
"new_page":(context) => NewRoute(),
"/":(context) => MyHomePage(title: 'Flutter Demo Home Page'), //注册首页路由
}
);
1.5.3. 3. 打开新路由页
可以使用Navigator 的pushNamed方法:
Future pushNamed(BuildContext context, String routeName,{Object arguments})
调用:
onPressed: () {
Navigator.pushNamed(context, "new_page");
//Navigator.push(context,
// MaterialPageRoute(builder: (context) {
// return NewRoute();
//}));
},
1.5.4. 4. 命名路由参数传递
传递参数:
Navigator.of(context).pushNamed("new_page", arguments: "hi");
获取路由参数:
@override
Widget build(BuildContext context) {
//获取路由参数
var args=ModalRoute.of(context).settings.arguments;
//...省略无关代码
}
1.5.5. 5. 带参数的路由
MaterialApp(
... //省略无关代码
routes: {
"tip2": (context){
return TipRoute(text: ModalRoute.of(context)!.settings.arguments);
},
},
);
1.6. 路由生成钩子
MaterialApp有一个onGenerateRoute属性,它在打开命名路由时可能会被调用,之所以说可能,是因为当调用Navigator.pushNamed(...)打开命名路由时,如果指定的路由名在路由表中已注册,则会调用路由表中的builder函数来生成路由组件;如果路由表中没有注册,才会调用onGenerateRoute来生成路由。onGenerateRoute回调签名如下:
Route<dynamic> Function(RouteSettings settings)
有了onGenerateRoute回调,要实现上面控制页面权限的功能就非常容易:我们放弃使用路由表,取而代之的是提供一个onGenerateRoute回调,然后在该回调中进行统一的权限控制,如:
MaterialApp(
... //省略无关代码
onGenerateRoute:(RouteSettings settings){
return MaterialPageRoute(builder: (context){
String routeName = settings.name;
// 如果访问的路由页需要登录,但当前未登录,则直接返回登录页路由,
// 引导用户登录;其他情况则正常打开路由。
}
);
}
);
onGenerateRoute onUnknownRoute区别:onGenerateRoute 无法生成路由,会触发OnUnknownRoute 属性来处理该场景。
注意,onGenerateRoute 只会对命名路由生效。也就是需要调用
Navigator.pushNamed
。