Flutter路由插件Fluro的使用

4 浏览发布于 作者 zouyang留下评论分享按钮

Flutter的路由机制很烦琐,如果是小型应用还勉强适用,但是真实开发中我们都会使用企业级的路由机制,让路由清晰可用。

Fluro是比较好的企业级Flutter路由。官方有使用介绍: https://pub.flutter-io.cn/packages/fluro 但是介绍的还不够详细。下面根据实战来记录下 Fluro 的使用姿势,分为两部分,第一部分是解释官网的使用步骤。第二部分是在实际项目中的一般使用步骤。

第一部分,解释官网的使用步骤,Fluro 按照官网的教程来看,步骤如下

1、在工程里引入 Fluro,在项目的 pubspec.yaml 内引入:

dependencies:
 fluro: "^1.6.3"

记得 pubspec.yaml 修改后,需要执行flutter命令 flutter pub get 一下哦。把包都下载进项目里才能使用。

2、在项目内实例化 Fluro 的一个路由实例出来:

import 'package:fluro/fluro.dart';
final router = Router();

3、为这个路由定义 路由名称 和 对应路由名称的处理逻辑:

定义路由:(这里 handler 传入的 是下面定义的那个处理程序usersHandler,意思就是 访问路由是”/users/:id” 则执行usersHandler这个处理操作)

router.define("/users/:id", handler: usersHandler);
处理程序:(这个处理程序是 返回 UsersScreen 这个组件)

处理路由逻辑的handler:(此处示例 handler 是 返回 UsersScreen 这个我们自定义的组件)

  var usersHandler = Handler(handlerFunc: (BuildContext context, Map<String, dynamic> params) {
    //...这里还可以进行一些操作,反正最后 return 一个我们路由跳转后需要显示的组件就OK
    return UsersScreen(params["id"][0]);
  });

至此,配置就完成了,路由器将拦截诸如之类的 /users/1234 路由,并将应用程序路由至 UsersScreen 将值 1234 作为参数传递给该屏幕的路由。以此类推,我们可以定义许多 不同路由的 处理。

4、那接下来怎么让项目使用上路由呢?如下:

在 MaterialApp 的配置参数中,设置 onGenerateRoute: router.generator。

@override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo', //任务管理上显示的名字
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      onGenerateRoute: router.generator, //这里配置使用 Fluro
      ……

这个 onGenerateRoute 参数是在“当跳转 命名路由 时找不到该路由,就会调用该方法”,所以这个 Fluro 其实就是通过自己封装的路由处理逻辑,然后在这里进行 各个路由的判断,然后根据判断返回不同的页面 来实现路由跳转的。

5、项目里进行路由跳转:

接下来,就可以用 Navigator.push 来跳转路由了。也可以自己手动推送到路线:

router.navigateTo(context, "/users/1234", transition: TransitionType.fadeIn);

transition 是跳转动画,它是可选命名参数,它还有一些值,比如 c: TransitionType.inFromLeft 等等,详见 transitionType 的定义源码如下:

enum TransitionType {
  native,
  nativeModal,
  inFromLeft,
  inFromRight,
  inFromBottom,
  fadeIn,
  custom, // if using custom then you must also provide a transition
  material,
  materialFullScreenDialog,
  cupertino,
  cupertinoFullScreenDialog,
}

另外,navigateTo 方法还有一些可选命名参数,下面源码的2-6行的参数,根据需要选择使用即可,比如那个 transitionDuration 就是表示路由跳转动画过渡的时间,clearStack 表示跳转后是否清除路由栈等等:

Future navigateTo(BuildContext context, String path,
      {bool replace = false,
      bool clearStack = false,
      TransitionType transition,
      Duration transitionDuration = const Duration(milliseconds: 250),
      RouteTransitionsBuilder transitionBuilder}) {
    RouteMatch routeMatch = matchRoute(context, path,
        transitionType: transition,
        transitionsBuilder: transitionBuilder,
        transitionDuration: transitionDuration);
    Route<dynamic> route = routeMatch.route;
    Completer completer = Completer();
    Future future = completer.future;
    if (routeMatch.matchType == RouteMatchType.nonVisual) {
      completer.complete("Non visual route type.");
    } else {
      if (route == null && notFoundHandler != null) {
        route = _notFoundRoute(context, path);
      }
      if (route != null) {
        if (clearStack) {
          future =
              Navigator.pushAndRemoveUntil(context, route, (check) => false);
        } else {
          future = replace
              ? Navigator.pushReplacement(context, route)
              : Navigator.push(context, route);
        }
        completer.complete();
      } else {
        String error = "No registered route was found to handle '$path'.";
        print(error);
        completer.completeError(RouteNotFoundException(error, path));
      }
    }

    return future;
  }




第二部分,项目中实际应用

1、一般我们把第一部分的第二步实例化的 router 放入一个类里来定义,把 Fluro 的 Router 静态化,方便今后项目里全局调用:创建一个 Application 类

import 'package:fluro/fluro.dart';
class Application {
  static Router router;
}

官方示例代码:
https://github.com/theyakka/fluro/blob/master/example/lib/config/application.dart

2、新建一个类,在里面封装所有的 处理路由的逻辑程序 handler

官方示例代码:
https://github.com/theyakka/fluro/blob/master/example/lib/config/route_handlers.dart

3、新建一个类,在里面封装所有的 定义路由 ,该类名字为 Routes 的类,该类里面因为会使用上一步的 handler,所以需要引入上一步的 handler 的类到此文件内

官方示例代码:
https://github.com/theyakka/fluro/blob/master/example/lib/config/routes.dart
这里面还配置了 找不到路由时的处理,就是那个 router.notFoundHandler

4、项目里使用时,只需引入 第1步和第3步 定义的2个类即可。然后就是实例化 router 并使用了:

    final router = Router();
    Routes.configureRoutes(router); //configureRoutes 是我们自定义的一个static 方法,用来结合 定义路由和路由处理逻辑的handler
    Application.router = router; //Application 的 router 是static

最后就是在 MaterialApp 组件内使用:

 MaterialApp(
      title: 'Fluro',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      onGenerateRoute: Application.router.generator, //使用 Fluro
    );

现在,我们要在哪里用路由,就引入最初静态化的 Application 类即可:

import './routers/application.dart';

在需要执行路由跳转的地方撸上即可实现路由跳转,比如:

Application.router.navigateTo(context,"/users/1234"); 


PS:

1、如何回传值:《futter 技术入门与实战》第二版11.2节 示例代码如下:

    Routes.router.navigateTo(
        context, '${Routes.page2}?message=$json',//跳转路径
        transition: TransitionType.inFromRight//过场效果
    ).then(   (result) {     //回传值
      if (result != null) {
        message = result;
      }
    }
   );

在页面内进行跳转时,可以 .then,定义好 用于第二个页面跳转回来时接收数据的处理逻辑。为什么可以.then ,是因为 本文第一部分第5点贴的 navigateTo 的源码可以看到,navigateTo 返回的是 Future。

第二个页面使用 Navigator.pop() 方法来回传数据,

Navigator.pop() 方法,会从导航器堆栈上移除 Route 对象。也就是返回上一个路由,使用 Navigator.pop(context); 它还有第二个可选参数,该参数为页面关闭时返回给上一个页面的数据。

Navigator.pop(context, '来自第二个界面的数据')

2、路由跳转时的参数传递与参数逻辑处理

1)参数如何传递到新路由页面那边呢?

路由跳转时通过 路由url 来传

router.define("/users/:id", handler: usersHandler);

更多的路由传参的url定义,可以看官方示例代码:https://github.com/theyakka/fluro/blob/master/example/lib/config/routes.dart
handler 里面通过 params 来获取并处理,请看下面 handler 处理参数

2)如何处理接收到的上一个路由页面传递过来的数据呢?
通过官方 handler 示例就可以看出 参数的处理都是在这里进行,Handler 的 handlerFunc 参数内可以处理传递的参数:https://github.com/theyakka/fluro/blob/master/example/lib/config/route_handlers.dart

var demoRouteHandler = Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
  String message = params["message"]?.first;  //处理参数
  String colorHex = params["color_hex"]?.first;
  String result = params["result"]?.first;
  Color color = Color(0xFFFFFFFF);
  if (colorHex != null && colorHex.length > 0) {
    color = Color(ColorHelpers.fromHexString(colorHex));
  }
  return DemoSimpleComponent(message: message, color: color, result: result);  //使用参数
});

想要打赏,请点击这里

发表评论

电子邮件地址不会被公开。 必填项已用*标注