https://pub.dev/packages/fluro
https://github.com/lukepighetti/fluro

Fluro作为一款优秀的Flutter企业级路由框架,Fluro的使用比官方提供的路由框架要复杂一些,但是却非常适合中大型项目。

依赖

  1. dependencies:
  2. fluro: ^1.7.8
  3. # 如果无法使用上面的方式添加Fluro依赖,还可以使用git的方式添加Fluro依赖
  4. dependencies:
  5. fluro:
  6. git: git://github.com/theyakka/fluro.git

导入

  1. import 'package:fluro/fluro.dart';

使用

lib/main.dart

  1. import "package:flutter/material.dart";
  2. import 'package:fluro/fluro.dart';
  3. import 'package:app1/routes/routes.dart';
  4. import 'package:app1/routes/application.dart';
  5. void main() {
  6. final router = FluroRouter(); //实例化路由
  7. Routes.configureRoutes(router); //导入路由
  8. Application.router = router; //路由静态化,以方便全局调用
  9. runApp(MyApp());
  10. }
  11. class MyApp extends StatelessWidget {
  12. @override
  13. Widget build(BuildContext context) {
  14. return MaterialApp(
  15. initialRoute: '/', //默认路由
  16. onGenerateRoute: Application.router.generator,
  17. );
  18. }
  19. }

lib/routes/application.dart 路由静态化

  1. import 'package:fluro/fluro.dart';
  2. class Application {
  3. static FluroRouter router;
  4. }

lib/routes/routes.dart 静态路由总体配置

  1. import 'package:fluro/fluro.dart';
  2. import 'package:app1/routes/application.dart';
  3. import 'package:app1/routes/route_handles.dart';
  4. class Routes {
  5. static configureRoutes(FluroRouter router) {
  6. // 没有发现路由页面时处理
  7. router.notFoundHandler = Handler(
  8. handlerFunc: (context, params) {
  9. return Text('没有发现路由页面 $params');
  10. },
  11. );
  12. router.define('/', handler: appStartHandler); // 启动页(动画结束后,自动跳至首页)
  13. router.define('/home', handler: homeHandler); // 首页
  14. router.define('/test', handler: testHandler);
  15. router.define('/search', handler: searchHandler);
  16. router.define('/webview', handler: webviewHandler);
  17. }
  18. /*
  19. * 对参数进行encode,解决参数中有特殊字符; Fluro会自动解码,不需再额外处理。
  20. * 示例 1: Routes.navigateTo(context, '/aa', params: {id: 1, title: '我是中文标题'});
  21. * 示例 2: Routes.navigateTo(context, '/aa', arguments: {id: 1, title: '我是中文标题'});
  22. *
  23. * 注意:params方式、RouteSettings方式不能并存,传参时优先考虑使用params方式;
  24. * 如果params不满足使用,再用RouteSettings方式。例如首页"/",无法使用params传参,即可使用RouteSettings方式.
  25. */
  26. static Future navigateTo(
  27. BuildContext context,
  28. String path, { //路由名称
  29. Map<String, dynamic> params, //search参数
  30. bool replace = false, //是否替换当前路由栈
  31. bool clearStack = false, //是否清空路由栈
  32. Duration transitionDuration = const Duration(milliseconds: 250), //动画周期
  33. RouteTransitionsBuilder transitionBuilder,
  34. TransitionType transition = TransitionType.material, //动画方式
  35. Map arguments, //RouteSettings 方式传参
  36. }) async {
  37. String query = "";
  38. if (params != null) {
  39. int index = 0;
  40. for (var key in params.keys) {
  41. if (params[key] != null) {
  42. var value = Uri.encodeComponent(params[key].toString());
  43. if (index == 0) {
  44. query = "?";
  45. } else {
  46. query = query + "\&";
  47. }
  48. query += "$key=$value";
  49. index++;
  50. }
  51. }
  52. }
  53. path = path + query;
  54. print('跳转的页面 => $path'); //我是navigateTo传递的参数:?id=11&title=%E6%9C%B1%E6%9C%9D%E9%98%B3
  55. return Application.router.navigateTo(
  56. context,
  57. path,
  58. replace: replace, // 是否替换当前页面
  59. clearStack: clearStack, // 是否情况页面存储栈信息
  60. transitionDuration: transitionDuration,
  61. transitionBuilder: transitionBuilder,
  62. transition: transition,
  63. routeSettings: arguments == null
  64. ? null
  65. : RouteSettings(arguments: arguments),
  66. );
  67. }
  68. static pop(context, [params]) {
  69. Application.router.pop(context, params);
  70. }
  71. }
  72. /*
  73. * TransitionType.inFromLeft //左侧进入
  74. * TransitionType.inFromRight //右侧进入
  75. * TransitionType.inFromBottom //底部进入 默认入场动画
  76. * TransitionType.native //无进入动画
  77. * TransitionType.nativeModal //同上
  78. * TransitionType.fadeIn //渐显动画
  79. * TransitionType.custom //自定义
  80. * TransitionType.material //感觉和上面几种一样 无特别动画效果
  81. * TransitionType.materialFullScreenDialog //感觉和上面几种一样 无特别动画效果
  82. * TransitionType.cupertino //右进右出
  83. * TransitionType.cupertinoFullScreenDialog //底部进 底部出 下个页面返回值变化
  84. */

lib/routes/route_handles.dart 路由handler配置

最终2种传参方式(params、routeSettings)的参数,再通过 构造函数 方式 传给路由页面组件。

  1. import 'package:flutter/material.dart';
  2. import 'package:fluro/fluro.dart';
  3. import 'package:app1/pages/app_start/index.dart';
  4. import 'package:app1/pages/home/index.dart';
  5. import 'package:app1/pages/search/index.dart';
  6. import 'package:app1/pages/web_view/index.dart';
  7. import 'package:app1/pages/test/index.dart';
  8. // app-启动页
  9. var appStartHandler = Handler(
  10. handlerFunc: (BuildContext context, Map<String, List<String>> params) {
  11. return AppStart();
  12. },
  13. );
  14. // 首页(params 方式传参)
  15. var homeHandler = Handler(
  16. handlerFunc: (context, params) {
  17. var index = params['index']?.first;
  18. return HomePage(index: index);
  19. },
  20. );
  21. // 搜索页(routeSettings 方式传参示例页面)
  22. var searchHandler = Handler(
  23. handlerFunc: (context, params) {
  24. var args = context.settings.arguments;
  25. return SearchPage(args);
  26. },
  27. );
  28. // webview页面
  29. var webviewHandler = Handler(
  30. handlerFunc: (context, params) {
  31. var url = params['url']?.first;
  32. var title = params['title']?.first;
  33. var showAppBar = params['showAppBar']?.first == 'true' ? true : false;
  34. return WebviewPage(url: url, title: title, showAppBar: showAppBar);
  35. },
  36. );
  37. // 测试demo页面
  38. var testHandler = Handler(
  39. handlerFunc: (context, params) {
  40. return TestPage();
  41. },
  42. );

lib/pages/home/index.dart 接收参数

  1. class HomePage extends StatefulWidget {
  2. HomePage({
  3. key,
  4. this.index = '0',
  5. }) : super(key: key);
  6. final String index;
  7. @override
  8. _HomePageState createState() => _HomePageState();
  9. }
  10. ...

lib/routes/route_push.dart 跳转

  1. import 'package:flutter/material.dart';
  2. import 'package:app1/routes/routes.dart';
  3. import 'package:fluro/fluro.dart';
  4. class RoutePush {
  5. // 跳转到首页指定 tab RoutePush.home(context, index: 1);
  6. static home(
  7. context, {
  8. int index = 0, //底部导航索引
  9. }) {
  10. Routes.navigateTo(
  11. context,
  12. '/home',
  13. clearStack: true,
  14. params: {
  15. 'index': index,
  16. },
  17. );
  18. }
  19. // 跳转到搜索页面(routeSettings方式传参示例页面) RoutePush.search(context, q: 'abc');
  20. static search(
  21. context, {
  22. String q = '', //搜索文本
  23. }) {
  24. Routes.navigateTo(
  25. context,
  26. '/search',
  27. arguments: {
  28. 'q': q,
  29. },
  30. );
  31. }
  32. // 跳转webview页面 RoutePush.webview(context, url: 'https://www.baidu.com', title: '百度');
  33. static webview(
  34. BuildContext context, {
  35. @required String url, //网页链接
  36. String title = '', //页面标题
  37. bool showAppBar = true, //是否展示appBar
  38. }) {
  39. Routes.navigateTo(
  40. context,
  41. '/webview',
  42. params: {'url': url, 'title': title, 'showAppBar': showAppBar},
  43. );
  44. }
  45. }

传参

直接通过链接传参

handler配置

  1. // webview页面
  2. var webviewHandler = Handler(
  3. handlerFunc: (context, params) {
  4. var url = params['url']?.first;
  5. var title = params['title']?.first;
  6. var showAppBar = params['showAppBar']?.first == 'true' ? true : false;
  7. return WebviewPage(url: url, title: title, showAppBar: showAppBar);
  8. },
  9. );

跳转

  1. Application.router.navigateTo(
  2. context,
  3. '/webview?url=${Uri.encodeComponent(https://www.baidu.com)}&showAppBar=true',
  4. );

接收

  1. class ApiDemoPage extends State<ApiDemoPage> {
  2. String title;
  3. String id;
  4. String isShare;
  5. ApiDemoPage({key, this.title, this.id, this.isShare}) : super(key: key);
  6. _getData() {
  7. print('${title} -- ${id} -- ${isShare}'); //zhu -- 11 -- null
  8. }
  9. //...
  10. }

通过 RouteSettings 传参

handler配置

  1. var searchHandler = Handler(
  2. handlerFunc: (context, params) {
  3. var args = context.settings.arguments; //args {id: 11, title: zhu}
  4. return SearchPage(args);
  5. },
  6. );

跳转

  1. Application.router.navigateTo(
  2. context,
  3. '/search',
  4. routeSettings: RouteSettings(
  5. arguments: {
  6. 'id': 11,
  7. 'title': 'zhu',
  8. },
  9. ),
  10. );

search.dart 接收

  1. class SearchPage extends StatelessWidget {
  2. final args;
  3. SearchPage(this.args);
  4. @override
  5. Widget build(BuildContext context) {
  6. print('args $args'); //args {id: 11, title: zhu}
  7. return null;
  8. }
  9. }

传参Map处理

传参前转为json字符串,接收时,再解码。

Application.router.pop() 返回

  1. /// 返回上一个页面
  2. static pop() {
  3. // 全局 context
  4. BuildContext myContext = navigatorKey.currentState.overlay.context;
  5. router.pop(myContext);
  6. }
  7. //这里设置了一个全局 context,如果没有设置,直接把 context 传入就行了。
  8. Application.router.pop(context);
  9. Application.router.pop(context, 1);

取得全局 Context

https://www.yuque.com/zhuchaoyang/tnyvrp/iisqnz/