路由
显式路由
需要在根组件下手动声明
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/', // 默认加载的路由,默认值为 '/'
routes: {
// 显式声明路由
'/': (context) => RootPage(),
'/A': (context) => Apage(),
'/B': (context) => Bpage(),
'/C': (context) => Cpage(),
},
// home: RootPage(),
);
}
}
注意:'/': (context) => RootPage() 和 home: RootPage() 不能同时存在
静态路由跳转
方法名中带 Name 的大多数是通过静态路由完成跳转的
Navigator.of(context).pushNamed('/A');
Navigator.of(context).pushReplacementNamed('/A');
Navigator.of(context).pushNamedAndRemoveUntil('/A');
动态路由跳转
动态路由可随时使用,无需在根组件的 routes 中注册
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Apage(),
));
动态路由需要传入一个 Route,示例中使用的是 MaterialPageRoute,它可以使用和平台风格一致的路由切换动画(iOS 左右,Android 上下),也可使用 CupertinoPageRoute 实现全平台的左右滑动,使用 PageRouteBuilder 可自定义动画
Navigator.of(context).push(
PageRouteBuilder(
transitionDuration: Duration(milliseconds: 250), // 动画时长 250 毫秒
pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) {
// 渐隐渐入过渡动画
return FadeTransition(
opacity: animation,
child: Apage(),
);
}
)
)
相关方法说明
pop
返回当前路由栈的上一个界面
Navigator.pop(context)
push / pushNamed
基础路由跳转,将一个 page 压入路由栈中,在原来的路由栈上添加一个新的 page
Navigator.of(context).pushNamed('/A');
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Apage(),
))
pushReplacement / pushReplacementNamed / popAndPushNamed
替换路由跳转,将当前路由替换掉再跳转(即当前路由不会出现在路由栈中)。popAndPushNamed 的动画效果不一样
Navigator.of(context).pushReplacementNamed('/A');
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => Apage(),
))
Navigator.of(context).popAndPushNamed('/A');
pushAndRemoveUntil / pushNamedAndRemoveUntil
按次序移除其他的路由,直到遇到被标记的路由(predicate 函数返回了 true)时停止
- 根据
predicate的返回值决定新路由之前的路由的处理方式true:保持不变false:则新路由外的所有路由都删掉
- 若没有标记的路由,则全部移除
- 当存在重复的标记时,默认移除到最近的一个时停止
移除全部
// 第一种
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => Cpage()),
(Route route) => route == null
);
// 第二种
Navigator.of(context).pushNamedAndRemoveUntil(
'/C',
(Route route) => route == null
);
移除到 RootPage 停止
// 第一种
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => Cpage()),
ModalRoute.withName('/')
);
// 仅写法不同
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => Cpage()),
(Route route) => route.settings.name == '/'
);
// 第二种
Navigator.of(context).pushNamedAndRemoveUntil(
'/C',
(Route route) => route.settings.name == '/'
);
// 仅写法不同
Navigator.of(context).pushNamedAndRemoveUntil(
'/C',
ModalRoute.withName('/')
);
popUntil
返回到指定的标记路由,若标记的路由为 null,则程序退出
Navigator.of(context).popUntil((route) => route.settings.name == '/');
Navigator.of(context).popUntil(ModalRoute.withName('/'));
// 返回根路由
Navigator.of(context).popUntil((route) => route.isFirst);
若标记的路由为动态路由,可在跳转到标记路由的时候设置一下,这样在返回时即可直接调用。示例如下
// 设置 Apage 的 RouteSettings
Navigator.of(context).push(MaterialPageRoute(
settings: RouteSettings(name: '/A'),
builder: (context) => Apage(),
))
// 在 Cpage 需要返回时调用即可
Navigator.of(context).popUntil(ModalRoute.withName('/A'));
canPop
判断是否可以导航到新页面,返回 bool 类型,通常是在设备带返回的物理按键时需要判断是否可以 pop
Navigator.of(context).canPop();
maybePop
canPop 的升级版本,如果当前路由可弹出则自动执行,否则不执行
removeRoute / removeRouteBelow
删除路由,同时执行 Route.dispose 操作,无过渡动画,正在进行的手势也会被取消。removeRouteBelow 删除指定路由下面的第一个路由,当对应的路由不存在时会报错
Navigator.of(context).removeRoute(route);
Navigator.of(context).removeRouteBelow(currentRoute, predicate);
路由传值
向下级路由传值
- 构造函数传值
个人感觉比较麻烦
// 构造一个可以带参数的构造函数
class Apage extends StatefulWidget {
String title;
Apage(this.title);
ApageState createState() => ApageState();
Widget build(BuildContext context) {
return Container(
child: Text(widget.title) // 使用 'widget.参数名' 获取
)
}
}
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Apage('这是传入的参数'),
))
ModalRoute传值
Navigatro.of(context).push(MaterialPageRoute(
settings: RouteSettings(name: '/A', arguments: {'argms': '这是传入的参数'}),
builder: (context) => Apage(),
))
// 或
Navigator.of(context).pushNamed('/A', arguments: {'argms': '这是传入的参数'});
// 在 Apage 中取值
class Apage extends StatelessWidget {
Widget build(BuildContext context) {
final params = ModalRoute.of(context).settings.arguments
return Container(
// ...
)
}
}
返回上级路由时传值
Navigator.of(context).pop('这是pop返回的参数');
// 在上一级路由获取
final result = await Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Cpage()
))
// 或
String value = await Navigator.of(context).pushNamed('/C');