Flutter的SPA实战,路由拦截器,全局Toast Loading

2,469 阅读2分钟

全局Toast/Loading问题

在Flutter开发中,全局的Toast/Loading很狗血,实现已有的实现方法都不是很人性化。最近在Dio做请求拦截器的时候Overlay一直获取不到context,每个页面进入都存一遍很不方便,如果在MaterialApp中存context,那么调用Navigator.of(context).pushReplacementNamedremoveUtils的操作时都会报错。

全局自定义命名路由动画问题

除了以上坑点。在使用命名路由的时候动画Flutter也没提供修改方法。Navigator.pushNamed(context, "/login");如果是android那么动画就是从下而上,一点都不fashion。

页面路由拦截器问题

Flutter的路由很特殊,如果想实现一个Router钩子要怎么办呢? - -!我就是样拦截路由,无论是埋点或者是以前其他特殊功能。都需要一个统一的路由调度。

解决思路

为了解决上面的Flutter坑点,联系Web端非常流行的SPA应用,如果我们的页面一直是单页那么context就是全局的。而且可以实现页面的拦截器。非常nice

SPA 单页面应用解决方案

直接上代码,首先实现一个单页的页面管理器。 so easy...

    MaterialApp(
        home: ManagerPage(),
        // ...
      )

然后是页面管理器ManagerPage的实现,利用Flutter自带的Navigator,不熟悉的童鞋可以看看我以前写的关于Navigator的文章。

    Widget build(BuildContext context) {
        // 利用 EventBus 来调度
        eventBus.on('showToast', (message) {
            Toast.show(context, message);
        });
        
        return Navigator( // 实现SPA
          initialRoute: '/',
          onGenerateRoute: (RouteSettings settings) {
    
            // 路由表对应单页
            Widget _page = ZRouter.routerStore[settings.name];
            
            // 埋点等操作
            
            // 自定义路由动画
            return CupertinoPageRoute(
              settings: settings,
              builder: (context) => _page
            );
          }
        );
    }

关于routerStore,一个SPA路由表

    static Map<String, Widget> get routerStore => {
        '/': SplashPage(),
        '/main_page': NavPage(),
        '/login': LoginPage(),
        '/product_detail': ProductDetailsPage()
      };

在子页面使用

    // 直接通过 Navigator.pushNamed 命名路由和传参。
    Navigator.pushNamed(context, "/login", arguments: RouteArguments<String>('想从活动登陆'));
    
    // 使用全局toast
    eventBus.emit('showToast', '系统繁忙请稍后再试...');

对请求拦截器的适配

    onResponse: (Response response) {
      // 在返回响应数据之前做一些预处理
      if (response.data['code'] != '000') {
        eventBus.emit('showToast', '系统繁忙请稍后再试...');
      }
      return response;
    },
    onError: (DioError error) {
      // 当请求失败时做一些预处理
      eventBus.emit('showToast', '程序员GG正在想问题...');
      return error;
    }

源码 github.com/zhongmeizhi…

觉得有用 star 一下哦