原生路由

初始化

在MyApp的build方法中添加常规路由处理方法onGenerateRoute,未知路由处理方法onUnknownRoute,以及定义初始路由initialRoute。

  1. class MyApp extends StatelessWidget {
  2. const MyApp({Key? key}) : super(key: key);
  3. // This widget is the root of your application.
  4. @override
  5. Widget build(BuildContext context) {
  6. return MaterialApp(
  7. title: 'Flutter Demo',
  8. theme: ThemeData(
  9. primarySwatch: Colors.blue,
  10. ),
  11. initialRoute: 'splash',
  12. onGenerateRoute: onGenerateRoute,
  13. onUnknownRoute: onUnknownRoute,
  14. );
  15. }
  16. }
  17. //固定写法
  18. var onGenerateRoute = (RouteSettings settings) {
  19. final String name = settings.name ??"404";
  20. final Function pageContentBuilder = routes[name] as Function;
  21. if (pageContentBuilder != null) {
  22. if (settings.arguments != null) {
  23. final Route route = MaterialPageRoute(
  24. builder: (context) =>
  25. pageContentBuilder(context, arguments: settings.arguments));
  26. return route;
  27. } else {
  28. final Route route =
  29. MaterialPageRoute(builder: (context) => pageContentBuilder(context));
  30. return route;
  31. }
  32. }
  33. };
  34. // 未知路由
  35. var onUnknownRoute = (RouteSettings settings) {
  36. final String name = "404";
  37. final Function pageContentBuilder = routes[name] as Function;
  38. if (pageContentBuilder != null) {
  39. final Route route =
  40. MaterialPageRoute(builder: (context) => pageContentBuilder(context));
  41. return route;
  42. }
  43. };
  44. final routes = {
  45. '404': (context) => NotFoundPage(),/// 404 notfound
  46. /// 往这里加
  47. };

添加了onGenerateRoute之后,Flutter的路由优先执行onGenerateRoute方法,initialRoute配置的初始路由也是通过onGenerateRoute去查找。当代码传递的路由名称在routes中找不到时,就会执行onUnknownRoute方法,跳转到自定义未知路由。

跳转

使用Navigator.pushNamed 跳转到指定的路由。

  1. Navigator.pushNamed(context, 'RouteName',arguments: 携带的数据);

这是Navigator.pushNamed方法的源码:

  1. @optionalTypeArgs
  2. static Future<T?> pushNamed<T extends Object?>(
  3. BuildContext context,
  4. String routeName, {
  5. Object? arguments,
  6. }) {
  7. return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
  8. }

返回的是一个 Future类型,所以可以使用.then来监听返回值,相当于实现了Android中的onActivityResult:

  1. Navigator.pushNamed(context, 'RouteName',arguments: 携带的数据)
  2. .then((value) {
  3. // todo something
  4. });

关闭页面

使用Navigator.pop来关闭当前页面。

  1. Navigator.pop(context);

这是Navigator.pop方法的源码:

  1. @optionalTypeArgs
  2. static void pop<T extends Object?>(BuildContext context, [ T? result ]) {
  3. Navigator.of(context).pop<T>(result);
  4. }

若果需要带参返回,则将参数赋值给result,由Navigator.pushNamed().then接收数据。如:

  1. Navigator.pop(context,data);

其他方法

  • popAndPushNamed 关闭当前页并根据名称跳转到指定页
  • pushReplacementNamed 根据名称更换当前路由堆栈
  • pushNamedAndRemoveUntil 根据名称跳转指定页并移除之前的路由堆栈(将跳转到的页面作为根路由)
  • push 跳转到指定页
  • pushReplacement 更换当前路由堆栈
  • pushAndRemoveUntil 跳转指定页并移除之前的路由堆栈(将跳转到的页面作为根路由)
  • replace 替换路由
  • replaceRouteBelow 更换路由路线
  • popUntil 关闭所有路由
  • removeRoute 移除路由
  • removeRouteBelow 移除路由路线
  • canPop 判断当前页面是否可关闭

GetX(推荐使用)※

getx是一款功能强大的插件,路由管理是其中一项功能。

初始化

在pubspec.yaml中引入getx,当前使用的版本为4.3.4。

  1. dependencies:
  2. flutter:
  3. sdk: flutter
  4. # The following adds the Cupertino Icons font to your application.
  5. # Use with the CupertinoIcons class for iOS style icons.
  6. cupertino_icons: ^1.0.2
  7. get: ^4.3.4 # 路由和状态管理

在main.dart的MyApp中使用GetMaterialApp替换原有的MaterialApp:

  1. void main() {
  2. runApp(MyApp());
  3. }
  4. class MyApp extends StatelessWidget {
  5. @override
  6. Widget build(BuildContext context) {
  7. return GetMaterialApp(
  8. title: 'Flutter Demo',
  9. theme: ThemeData(
  10. primarySwatch: Colors.blue,
  11. ),
  12. home: HomePage(),
  13. );
  14. }
  15. }

跳转

使用 Get.to(()=>Page()) (或Get.to(Page()) ,没有其他参数的情况下推荐使用前者) 实现跳转,表示从当前页面跳转到Page页面,也可以使用Get.toNamed(‘path’):

  1. Get.to(()=>Page()) ; // Get.to(Page());
  2. Get.toNamed('path');

使用Get.to可以在Page()中传递构造参数,也可以使用get中的arguments传参:

  1. Get.to(Page(data:data),arguments: data);
  2. Get.toNamed('path',arguments: data); ///Get.toNamed 不能使用构造参数传值

如果使用Get.toNamed,需要配置path解析方法getPages:

  1. class MyApp extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return GetMaterialApp(
  5. title: 'Flutter Demo',
  6. theme: ThemeData(
  7. primarySwatch: Colors.blue,
  8. ),
  9. initialRoute: '/home',
  10. getPages: getPageList,
  11. );
  12. }
  13. }
  14. var getPageList = [GetPage(name: '/home', page: () => HomePage()),];

getPageList是个数组,按GetPage(name: ‘/home’, page: () => HomePage()),格式往里边添加即可。
相同的,Get.to方法返回一个Future?,可以使用.then来监听返回值:

  1. Get.to(()=>HomePage())?.then((value) {
  2. ScaffoldMessenger.of(context).showSnackBar(
  3. SnackBar(
  4. content: Text('返回值为:$value'),
  5. ),// 弹出底部提示框,显示返回值
  6. );
  7. });

关闭页面

关闭当前页面:

  1. Get.back();

关闭当前页面并跳转到新页面:

  1. Get.off(()=>Page());
  2. Get.offNamed('path');

清除所有路由并跳转到新页面(以新页面作为根节点):

  1. Get.offAll(()=>Page());
  2. Get.offAllNamed('path');

其他方法

其他用法和原生相似,具体方法可在getx的GetNavigation类中查询,附上源码:

  1. extension GetNavigation on GetInterface {
  2. /// **Navigation.push()** shortcut.<br><br>
  3. ///
  4. /// Pushes a new `page` to the stack
  5. ///
  6. /// It has the advantage of not needing context,
  7. /// so you can call from your business logic
  8. ///
  9. /// You can set a custom [transition], and a transition [duration].
  10. ///
  11. /// You can send any type of value to the other route in the [arguments].
  12. ///
  13. /// Just like native routing in Flutter, you can push a route
  14. /// as a [fullscreenDialog],
  15. ///
  16. /// [id] is for when you are using nested navigation,
  17. /// as explained in documentation
  18. ///
  19. /// If you want the same behavior of ios that pops a route when the user drag,
  20. /// you can set [popGesture] to true
  21. ///
  22. /// If you're using the [Bindings] api, you must define it here
  23. ///
  24. /// By default, GetX will prevent you from push a route that you already in,
  25. /// if you want to push anyway, set [preventDuplicates] to false
  26. Future<T?>? to<T>(
  27. dynamic page, {
  28. bool? opaque,
  29. Transition? transition,
  30. Curve? curve,
  31. Duration? duration,
  32. int? id,
  33. String? routeName,
  34. bool fullscreenDialog = false,
  35. dynamic arguments,
  36. Bindings? binding,
  37. bool preventDuplicates = true,
  38. bool? popGesture,
  39. double Function(BuildContext context)? gestureWidth,
  40. }) {
  41. // var routeName = "/${page.runtimeType}";
  42. routeName ??= "/${page.runtimeType}";
  43. routeName = _cleanRouteName(routeName);
  44. if (preventDuplicates && routeName == currentRoute) {
  45. return null;
  46. }
  47. return global(id).currentState?.push<T>(
  48. GetPageRoute<T>(
  49. opaque: opaque ?? true,
  50. page: _resolvePage(page, 'to'),
  51. routeName: routeName,
  52. gestureWidth: gestureWidth,
  53. settings: RouteSettings(
  54. name: routeName,
  55. arguments: arguments,
  56. ),
  57. popGesture: popGesture ?? defaultPopGesture,
  58. transition: transition ?? defaultTransition,
  59. curve: curve ?? defaultTransitionCurve,
  60. fullscreenDialog: fullscreenDialog,
  61. binding: binding,
  62. transitionDuration: duration ?? defaultTransitionDuration,
  63. ),
  64. );
  65. }
  66. GetPageBuilder _resolvePage(dynamic page, String method) {
  67. if (page is GetPageBuilder) {
  68. return page;
  69. } else if (page is Widget) {
  70. Get.log(
  71. '''WARNING, consider using: "Get.$method(() => Page())" instead of "Get.$method(Page())".
  72. Using a widget function instead of a widget fully guarantees that the widget and its controllers will be removed from memory when they are no longer used.
  73. ''');
  74. return () => page;
  75. } else if (page is String) {
  76. throw '''Unexpected String,
  77. use toNamed() instead''';
  78. } else {
  79. throw '''Unexpected format,
  80. you can only use widgets and widget functions here''';
  81. }
  82. }
  83. /// **Navigation.pushNamed()** shortcut.<br><br>
  84. ///
  85. /// Pushes a new named `page` to the stack.
  86. ///
  87. /// It has the advantage of not needing context, so you can call
  88. /// from your business logic.
  89. ///
  90. /// You can send any type of value to the other route in the [arguments].
  91. ///
  92. /// [id] is for when you are using nested navigation,
  93. /// as explained in documentation
  94. ///
  95. /// By default, GetX will prevent you from push a route that you already in,
  96. /// if you want to push anyway, set [preventDuplicates] to false
  97. ///
  98. /// Note: Always put a slash on the route ('/page1'), to avoid unnexpected errors
  99. Future<T?>? toNamed<T>(
  100. String page, {
  101. dynamic arguments,
  102. int? id,
  103. bool preventDuplicates = true,
  104. Map<String, String>? parameters,
  105. }) {
  106. if (preventDuplicates && page == currentRoute) {
  107. return null;
  108. }
  109. if (parameters != null) {
  110. final uri = Uri(path: page, queryParameters: parameters);
  111. page = uri.toString();
  112. }
  113. return global(id).currentState?.pushNamed<T>(
  114. page,
  115. arguments: arguments,
  116. );
  117. }
  118. /// **Navigation.pushReplacementNamed()** shortcut.<br><br>
  119. ///
  120. /// Pop the current named `page` in the stack and push a new one in its place
  121. ///
  122. /// It has the advantage of not needing context, so you can call
  123. /// from your business logic.
  124. ///
  125. /// You can send any type of value to the other route in the [arguments].
  126. ///
  127. /// [id] is for when you are using nested navigation,
  128. /// as explained in documentation
  129. ///
  130. /// By default, GetX will prevent you from push a route that you already in,
  131. /// if you want to push anyway, set [preventDuplicates] to false
  132. ///
  133. /// Note: Always put a slash on the route ('/page1'), to avoid unnexpected errors
  134. Future<T?>? offNamed<T>(
  135. String page, {
  136. dynamic arguments,
  137. int? id,
  138. bool preventDuplicates = true,
  139. Map<String, String>? parameters,
  140. }) {
  141. if (preventDuplicates && page == currentRoute) {
  142. return null;
  143. }
  144. if (parameters != null) {
  145. final uri = Uri(path: page, queryParameters: parameters);
  146. page = uri.toString();
  147. }
  148. return global(id).currentState?.pushReplacementNamed(
  149. page,
  150. arguments: arguments,
  151. );
  152. }
  153. /// **Navigation.popUntil()** shortcut.<br><br>
  154. ///
  155. /// Calls pop several times in the stack until [predicate] returns true
  156. ///
  157. /// [id] is for when you are using nested navigation,
  158. /// as explained in documentation
  159. ///
  160. /// [predicate] can be used like this:
  161. /// `Get.until((route) => Get.currentRoute == '/home')`so when you get to home page,
  162. ///
  163. /// or also like this:
  164. /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the
  165. /// dialog is closed
  166. void until(RoutePredicate predicate, {int? id}) {
  167. // if (key.currentState.mounted) // add this if appear problems on future with route navigate
  168. // when widget don't mounted
  169. return global(id).currentState?.popUntil(predicate);
  170. }
  171. /// **Navigation.pushAndRemoveUntil()** shortcut.<br><br>
  172. ///
  173. /// Push the given `page`, and then pop several pages in the stack until
  174. /// [predicate] returns true
  175. ///
  176. /// [id] is for when you are using nested navigation,
  177. /// as explained in documentation
  178. ///
  179. /// Obs: unlike other get methods, this one you need to send a function
  180. /// that returns the widget to the page argument, like this:
  181. /// Get.offUntil(GetPageRoute(page: () => HomePage()), predicate)
  182. ///
  183. /// [predicate] can be used like this:
  184. /// `Get.offUntil(page, (route) => (route as GetPageRoute).routeName == '/home')`
  185. /// to pop routes in stack until home,
  186. /// or also like this:
  187. /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the dialog
  188. /// is closed
  189. Future<T?>? offUntil<T>(Route<T> page, RoutePredicate predicate, {int? id}) {
  190. // if (key.currentState.mounted) // add this if appear problems on future with route navigate
  191. // when widget don't mounted
  192. return global(id).currentState?.pushAndRemoveUntil<T>(page, predicate);
  193. }
  194. /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
  195. ///
  196. /// Push the given named `page`, and then pop several pages in the stack
  197. /// until [predicate] returns true
  198. ///
  199. /// You can send any type of value to the other route in the [arguments].
  200. ///
  201. /// [id] is for when you are using nested navigation,
  202. /// as explained in documentation
  203. ///
  204. /// [predicate] can be used like this:
  205. /// `Get.offNamedUntil(page, ModalRoute.withName('/home'))`
  206. /// to pop routes in stack until home,
  207. /// or like this:
  208. /// `Get.offNamedUntil((route) => !Get.isDialogOpen())`,
  209. /// to make sure the dialog is closed
  210. ///
  211. /// Note: Always put a slash on the route name ('/page1'), to avoid unexpected errors
  212. Future<T?>? offNamedUntil<T>(
  213. String page,
  214. RoutePredicate predicate, {
  215. int? id,
  216. dynamic arguments,
  217. Map<String, String>? parameters,
  218. }) {
  219. if (parameters != null) {
  220. final uri = Uri(path: page, queryParameters: parameters);
  221. page = uri.toString();
  222. }
  223. return global(id).currentState?.pushNamedAndRemoveUntil<T>(
  224. page,
  225. predicate,
  226. arguments: arguments,
  227. );
  228. }
  229. /// **Navigation.popAndPushNamed()** shortcut.<br><br>
  230. ///
  231. /// Pop the current named page and pushes a new `page` to the stack
  232. /// in its place
  233. ///
  234. /// You can send any type of value to the other route in the [arguments].
  235. /// It is very similar to `offNamed()` but use a different approach
  236. ///
  237. /// The `offNamed()` pop a page, and goes to the next. The
  238. /// `offAndToNamed()` goes to the next page, and removes the previous one.
  239. /// The route transition animation is different.
  240. Future<T?>? offAndToNamed<T>(
  241. String page, {
  242. dynamic arguments,
  243. int? id,
  244. dynamic result,
  245. Map<String, String>? parameters,
  246. }) {
  247. if (parameters != null) {
  248. final uri = Uri(path: page, queryParameters: parameters);
  249. page = uri.toString();
  250. }
  251. return global(id).currentState?.popAndPushNamed(
  252. page,
  253. arguments: arguments,
  254. result: result,
  255. );
  256. }
  257. /// **Navigation.removeRoute()** shortcut.<br><br>
  258. ///
  259. /// Remove a specific [route] from the stack
  260. ///
  261. /// [id] is for when you are using nested navigation,
  262. /// as explained in documentation
  263. void removeRoute(Route<dynamic> route, {int? id}) {
  264. return global(id).currentState?.removeRoute(route);
  265. }
  266. /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
  267. ///
  268. /// Push a named `page` and pop several pages in the stack
  269. /// until [predicate] returns true. [predicate] is optional
  270. ///
  271. /// It has the advantage of not needing context, so you can
  272. /// call from your business logic.
  273. ///
  274. /// You can send any type of value to the other route in the [arguments].
  275. ///
  276. /// [predicate] can be used like this:
  277. /// `Get.until((route) => Get.currentRoute == '/home')`so when you get to home page,
  278. /// or also like
  279. /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the dialog
  280. /// is closed
  281. ///
  282. /// [id] is for when you are using nested navigation,
  283. /// as explained in documentation
  284. ///
  285. /// Note: Always put a slash on the route ('/page1'), to avoid unexpected errors
  286. Future<T?>? offAllNamed<T>(
  287. String newRouteName, {
  288. RoutePredicate? predicate,
  289. dynamic arguments,
  290. int? id,
  291. Map<String, String>? parameters,
  292. }) {
  293. if (parameters != null) {
  294. final uri = Uri(path: newRouteName, queryParameters: parameters);
  295. newRouteName = uri.toString();
  296. }
  297. return global(id).currentState?.pushNamedAndRemoveUntil<T>(
  298. newRouteName,
  299. predicate ?? (_) => false,
  300. arguments: arguments,
  301. );
  302. }
  303. /// Returns true if a Snackbar, Dialog or BottomSheet is currently OPEN
  304. bool get isOverlaysOpen =>
  305. (isSnackbarOpen! || isDialogOpen! || isBottomSheetOpen!);
  306. /// Returns true if there is no Snackbar, Dialog or BottomSheet open
  307. bool get isOverlaysClosed =>
  308. (!isSnackbarOpen! && !isDialogOpen! && !isBottomSheetOpen!);
  309. /// **Navigation.popUntil()** shortcut.<br><br>
  310. ///
  311. /// Pop the current page, snackbar, dialog or bottomsheet in the stack
  312. ///
  313. /// if your set [closeOverlays] to true, Get.back() will close the
  314. /// currently open snackbar/dialog/bottomsheet AND the current page
  315. ///
  316. /// [id] is for when you are using nested navigation,
  317. /// as explained in documentation
  318. ///
  319. /// It has the advantage of not needing context, so you can call
  320. /// from your business logic.
  321. void back<T>({
  322. T? result,
  323. bool closeOverlays = false,
  324. bool canPop = true,
  325. int? id,
  326. }) {
  327. if (closeOverlays && isOverlaysOpen) {
  328. navigator?.popUntil((route) {
  329. return (isOverlaysClosed);
  330. });
  331. }
  332. if (canPop) {
  333. if (global(id).currentState?.canPop() == true) {
  334. global(id).currentState?.pop<T>(result);
  335. }
  336. } else {
  337. global(id).currentState?.pop<T>(result);
  338. }
  339. }
  340. /// **Navigation.popUntil()** (with predicate) shortcut .<br><br>
  341. ///
  342. /// Close as many routes as defined by [times]
  343. ///
  344. /// [id] is for when you are using nested navigation,
  345. /// as explained in documentation
  346. void close(int times, [int? id]) {
  347. if (times < 1) {
  348. times = 1;
  349. }
  350. var count = 0;
  351. var back = global(id).currentState?.popUntil((route) => count++ == times);
  352. return back;
  353. }
  354. /// **Navigation.pushReplacement()** shortcut .<br><br>
  355. ///
  356. /// Pop the current page and pushes a new `page` to the stack
  357. ///
  358. /// It has the advantage of not needing context,
  359. /// so you can call from your business logic
  360. ///
  361. /// You can set a custom [transition], define a Tween [curve],
  362. /// and a transition [duration].
  363. ///
  364. /// You can send any type of value to the other route in the [arguments].
  365. ///
  366. /// Just like native routing in Flutter, you can push a route
  367. /// as a [fullscreenDialog],
  368. ///
  369. /// [id] is for when you are using nested navigation,
  370. /// as explained in documentation
  371. ///
  372. /// If you want the same behavior of ios that pops a route when the user drag,
  373. /// you can set [popGesture] to true
  374. ///
  375. /// If you're using the [Bindings] api, you must define it here
  376. ///
  377. /// By default, GetX will prevent you from push a route that you already in,
  378. /// if you want to push anyway, set [preventDuplicates] to false
  379. Future<T?>? off<T>(
  380. dynamic page, {
  381. bool opaque = false,
  382. Transition? transition,
  383. Curve? curve,
  384. bool? popGesture,
  385. int? id,
  386. String? routeName,
  387. dynamic arguments,
  388. Bindings? binding,
  389. bool fullscreenDialog = false,
  390. bool preventDuplicates = true,
  391. Duration? duration,
  392. double Function(BuildContext context)? gestureWidth,
  393. }) {
  394. routeName ??= "/${page.runtimeType.toString()}";
  395. routeName = _cleanRouteName(routeName);
  396. if (preventDuplicates && routeName == currentRoute) {
  397. return null;
  398. }
  399. return global(id).currentState?.pushReplacement(GetPageRoute(
  400. opaque: opaque,
  401. gestureWidth: gestureWidth,
  402. page: _resolvePage(page, 'off'),
  403. binding: binding,
  404. settings: RouteSettings(
  405. arguments: arguments,
  406. name: routeName,
  407. ),
  408. routeName: routeName,
  409. fullscreenDialog: fullscreenDialog,
  410. popGesture: popGesture ?? defaultPopGesture,
  411. transition: transition ?? defaultTransition,
  412. curve: curve ?? defaultTransitionCurve,
  413. transitionDuration: duration ?? defaultTransitionDuration));
  414. }
  415. ///
  416. /// Push a `page` and pop several pages in the stack
  417. /// until [predicate] returns true. [predicate] is optional
  418. ///
  419. /// It has the advantage of not needing context,
  420. /// so you can call from your business logic
  421. ///
  422. /// You can set a custom [transition], a [curve] and a transition [duration].
  423. ///
  424. /// You can send any type of value to the other route in the [arguments].
  425. ///
  426. /// Just like native routing in Flutter, you can push a route
  427. /// as a [fullscreenDialog],
  428. ///
  429. /// [predicate] can be used like this:
  430. /// `Get.until((route) => Get.currentRoute == '/home')`so when you get to home page,
  431. /// or also like
  432. /// `Get.until((route) => !Get.isDialogOpen())`, to make sure the dialog
  433. /// is closed
  434. ///
  435. /// [id] is for when you are using nested navigation,
  436. /// as explained in documentation
  437. ///
  438. /// If you want the same behavior of ios that pops a route when the user drag,
  439. /// you can set [popGesture] to true
  440. ///
  441. /// If you're using the [Bindings] api, you must define it here
  442. ///
  443. /// By default, GetX will prevent you from push a route that you already in,
  444. /// if you want to push anyway, set [preventDuplicates] to false
  445. Future<T?>? offAll<T>(
  446. dynamic page, {
  447. RoutePredicate? predicate,
  448. bool opaque = false,
  449. bool? popGesture,
  450. int? id,
  451. String? routeName,
  452. dynamic arguments,
  453. Bindings? binding,
  454. bool fullscreenDialog = false,
  455. Transition? transition,
  456. Curve? curve,
  457. Duration? duration,
  458. double Function(BuildContext context)? gestureWidth,
  459. }) {
  460. routeName ??= "/${page.runtimeType.toString()}";
  461. routeName = _cleanRouteName(routeName);
  462. return global(id).currentState?.pushAndRemoveUntil<T>(
  463. GetPageRoute<T>(
  464. opaque: opaque,
  465. popGesture: popGesture ?? defaultPopGesture,
  466. page: _resolvePage(page, 'offAll'),
  467. binding: binding,
  468. gestureWidth: gestureWidth,
  469. settings: RouteSettings(
  470. name: routeName,
  471. arguments: arguments,
  472. ),
  473. fullscreenDialog: fullscreenDialog,
  474. routeName: routeName,
  475. transition: transition ?? defaultTransition,
  476. curve: curve ?? defaultTransitionCurve,
  477. transitionDuration: duration ?? defaultTransitionDuration,
  478. ),
  479. predicate ?? (route) => false);
  480. }
  481. /// 省略部分代码
  482. }