美文网首页
Flutter router

Flutter router

作者: whqfor | 来源:发表于2019-10-18 18:54 被阅读0次

    在Flutter开发的页面间实现跳转的话,一切都离不开Navigator,系统提供了Navigator管理界面跳转、传参、返回等操作,但是使用起来不太方便,比如router的注册需添加到routers中,如下左图,界面跳转的话需要引入目的页的类,获取当前context,在进行跳转,获取也是一样,都比较复杂。总结起来就是,耦合严重、不便使用,写小demo还感觉不到差别,当应用于完整项目的时候,耦合的问题就需要考虑了。

    获取.png 注册routers.png
    • 解耦
      解耦是在根据fluro这个库进行的,将flutter 路由表统一进行管理
      路由表.png

    基于这个库也可以做到了跳转一行代码

    DRouter.navigateTo(DartRouter.inviteFriend, isLogin: true);
    

    不过还不够,这个库本身也有一些限制,于是在此基础上进行了修改,仓库地址
    只支持scheme传参,这显然有很大的局限性,系统的Navigator是支持传参Object的,对比系统源码和库源码,扩展了 RouteSettings,基于此进行的一些改造可以支持Object传参,同时也保留了库本身基于scheme方式

    RouteSettings userSettings = RouteSettings(name: umpPath, arguments: arguments);
    
    • 便捷使用
      此外进行了方法的扩展,满足常见的跳转,此外还增加popUntilpopSkip的支持
    
      void popUntil(BuildContext context, String path) {
        serviceLocator.getIt<NavigateService>().popUntilG(ModalRoute.withName(path));
      }
    
      void popSkip(BuildContext context, String skip) {
        serviceLocator.getIt<NavigateService>().popUntilG(
            (Route<dynamic> route) {
              bool routePredicate = !route.willHandlePopInternally
                  && route is ModalRoute
                  && Uri.parse(route.settings.name).host != skip;
              if (!routePredicate) { // 双重否定为肯定
                // 包含则 skip 出栈
                print('popSkip $skip -- ${route.settings.name}');
              }
              return routePredicate;
            }
        );
      }
    

    其中popSkip是基于 RoutePredicate对fluro以及系统Navigator的创新,可以跳过某个模块,而不用关心来源是什么页面。

    • 无context导航
      @optionalTypeArgs
      static Future<T> pushNamed<T extends Object>(
        BuildContext context,
        String routeName, {
        Object arguments,
       }) {
        return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments);
      }
    

    Navigator的跳转的时候需要有上下文context,这是个重要的参数,在混合栈中提到会有native页面和flutter页面之间的相互跳转,那么就有如下问题,native跳转flutter的时候,native页面是没有context信息的,全局变量保存当前flutter页面的context信息也是不可取的。那么怎么实现无context导航呐?
    这里使用到了GlobalKey,GlobalKey可以保存widget,我们可以在程序的入口通过GlobalKey来保存flutter tree的根节点,这样就可以通过根节点进行任何页面内的跳转。

    // 获取根节点
    child: MaterialApp(
      navigatorKey: Application.serviceLocator.getIt<NavigateService>().key,
      home: ContainerPage(),
    
    // 获取NavigatorState
    class NavigateService {
      final GlobalKey<NavigatorState> key = GlobalKey(debugLabel: 'navigate_key');
      NavigatorState get navigator => key.currentState;
      get pushNamedG       => navigator.pushNamed;
      get pushG            => navigator.push;
      get pushReplacementG => navigator.pushReplacement;
      get popG             => navigator.pop;
      get popUntilG        => navigator.popUntil;
    }
    
    • NavigatorObserver
      flutter的所有ui都是由widget组成,生命周期也是基于widget的state,但是对于页面来说state生命周期还是比较弱,难以做到像native页面一样监控各种页面展示退出。这点可以通过NavigatorObserver进行解决,可以在程序初始化时设置navigatorObservers
    child: MaterialApp(
      navigatorKey: Application.serviceLocator.getIt<NavigateService>().key,
      home: ContainerPage(),
      debugShowCheckedModeBanner: false,
      onGenerateRoute: Application.router.generator,
      navigatorObservers: [AppRouterNavigatorObserver()],
    

    NavigatorObserver里面有丰富的api,didPush、didPop、didRemove、didStartUserGesture、didStopUserGesture等,举一个例子:

    void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { }
    

    两个参数Route,这样就可以根据router知道前一个页面后一个面是什么,可以在这里进行埋点之类的全局监控。

    • 两个路由表
      上面主要讲述了flutter router的管理,还不算真正的路由管理,路由管理这里不再阐述,和Native的路由功能一样。那两个路由表是是什么意思呐?flutter 页面维护一个路由表,主要是flutter页面是由Navigator进行管理跳转,此外如果涉及到混合栈,路由问题就复杂了一些,native的路由管理是由Native的导航栏进行的,所以针对native页面又建立了一个路由表,两个路由表结合在一起,构成了大路由的基础。当需要页面跳转的时候,先去两个路由中查找,目的页面是来自native页面还是flutter页面,再有响应的navigate进行处理,当然混合栈的问题还牵涉到通信,流程图如下:


      混合栈通信.png

    相关文章

      网友评论

          本文标题:Flutter router

          本文链接:https://www.haomeiwen.com/subject/ynbapctx.html