Flutter router

2019-10-18  本文已影响0人  whqfor

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

获取.png 注册routers.png

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

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

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

RouteSettings userSettings = RouteSettings(name: umpPath, arguments: arguments);

  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的创新,可以跳过某个模块,而不用关心来源是什么页面。

  @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;
}
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知道前一个页面后一个面是什么,可以在这里进行埋点之类的全局监控。

上一篇 下一篇

猜你喜欢

热点阅读