Flutter上线项目实战——路由篇

1. 应用场景

开发中常常遇到数组

  • 路由跳转时拿不到context怎么办,eg: token失效/异地登陆跳转登陆页面。
  • 获取不到当前路由名称怎么办,eg: 点击push推送跳转指定路由,若是已经在当前页面就replace,若是不在就push。
  • 注册监听路由跳转,作一些想作的事情 ,eg:不一样路由,显示不一样状态栏颜色。
  • 等等...

2. 解决方案

解决思路:ide

  1. MaterialApp 的routes属性赋值路由数组,navigatorObservers属性赋值路由监听对象NavigatorManager。
  2. 在NavigatorManager里实现NavigatorObserver的didPush/didReplace/didPop/didRemove,并记录到路由栈 List _mRoutes中。
  3. 将实时记录的路由跳转,用stream发一个广播,哪里须要哪里注册。

3. 具体实现

main.dartui

MaterialApp(
    navigatorObservers: [NavigatorManager.getInstance()],
    routes: NavigatorManager.configRoutes,
    ...
)
复制代码

navigator_manager.dartspa

class NavigatorManager extends NavigatorObserver {
  /* 配置routes */
  static Map<String, WidgetBuilder> configRoutes = {
  PackageInfoPage.sName: (context) =>
    SplashPage.sName: (context) => SplashPage(),
    LoginPage.sName: (context) => SplashPage()),
    MainPage.sName: (context) => SplashPage(),
    //...
  }
  // 当前路由栈
  static List<Route> _mRoutes;
  List<Route> get routes => _mRoutes;
  // 当前路由
  Route get currentRoute => _mRoutes[_mRoutes.length - 1];
  // stream相关
  static StreamController _streamController;
  StreamController get streamController=> _streamController;
  // 用来路由跳转
  static NavigatorState navigator;
  
  /* 单例给出NavigatorManager */
  static NavigatorManager navigatorManager;
  static NavigatorManager getInstance() {
    if (navigatorManager == null) {
      navigatorManager = new NavigatorManager();
      _streamController = StreamController.broadcast();
    }
    return navigatorManager;
  }
  
  // replace 页面
  pushReplacementNamed(String routeName, [WidgetBuilder builder]) {
    return navigator.pushReplacement(
      CupertinoPageRoute(
        builder: builder ?? configRoutes[routeName],
        settings: RouteSettings(name: routeName),
      ),
    );
  }
  
  // push 页面
  pushNamed(String routeName, [WidgetBuilder builder]) {
    return navigator.push(
      CupertinoPageRoute(
        builder: builder ?? configRoutes[routeName],
        settings: RouteSettings(name: routeName),
      ),
    );
  }
  
  // pop 页面
  pop<T extends Object>([T result]) {
    navigator.pop(result);
  }
  
  // push一个页面, 移除该页面下面全部页面
  pushNamedAndRemoveUntil(String newRouteName) {
    return navigator.pushNamedAndRemoveUntil(newRouteName, (Route<dynamic> route) => false);
  }
  
  // 当调用Navigator.push时回调
  @override
  void didPush(Route route, Route previousRoute) {
    super.didPush(route, previousRoute);
    if (_mRoutes == null) {
      _mRoutes = new List<Route>();
    }
    // 这里过滤调push的是dialog的状况
    if (route is CupertinoPageRoute || route is MaterialPageRoute) {
      _mRoutes.add(route);
      routeObserver();
    }
  }
  
  // 当调用Navigator.replace时回调
  @override
  void didReplace({Route newRoute, Route oldRoute}) {
    super.didReplace();
    if (newRoute is CupertinoPageRoute || newRoute is MaterialPageRoute) {
      _mRoutes.remove(oldRoute);
      _mRoutes.add(newRoute);
      routeObserver();
    }
  }
  
  // 当调用Navigator.pop时回调
  @override
  void didPop(Route route, Route previousRoute) {
    super.didPop(route, previousRoute);
    if (route is CupertinoPageRoute || route is MaterialPageRoute) {
      _mRoutes.remove(route);
      routeObserver();
    }
  }
  
  @override
  void didRemove(Route removedRoute, Route oldRoute) {
    super.didRemove(removedRoute, oldRoute);
    if (removedRoute is CupertinoPageRoute || removedRoute is MaterialPageRoute) {
      _mRoutes.remove(removedRoute);
      routeObserver();
    }
  }
  
  void routeObserver() {
    LogUtil.i(sName, '&&路由栈&&');
    LogUtil.i(sName, _mRoutes);
    LogUtil.i(sName, '&&当前路由&&');
    LogUtil.i(sName, _mRoutes[_mRoutes.length - 1]);
    // 当前页面的navigator,用来路由跳转
    navigator = _mRoutes[_mRoutes.length - 1].navigator;
    streamController.sink.add(_mRoutes);
  }
}
复制代码

4. 如何使用

token失效跳转code

case 401:
    ToastUtil.showRed('登陆失效,请从新登录');
    UserDao.clearAll();
    NavigatorManager.getInstance().pushNamedAndRemoveUntil(LoginPage.sName);
    break;
复制代码

点击push推送跳转server

static jumpPage(String pageName, [WidgetBuilder builder]) {
    String currentRouteName = NavigatorManager.getInstance().currentRoute.settings.name;
    // 若是是未登陆,不跳转
    if (NavigatorManager.getInstance().routes[0].settings.name != MainPage.sName) {
      return;
    }

    // 若是已是当前页面就replace
    if (currentRouteName == pageName) {
      NavigatorManager.getInstance().pushReplacementNamed(pageName, builder);
    } else {
      NavigatorManager.getInstance().pushNamed(pageName, builder);
    }
}
复制代码

监听路由改变状态栏颜色对象

class StatusBarUtil {
      static List<String> lightRouteNameList = [
        TaskhallPage.sName,
        //...
      ];
      static List darkRoutNameList = [
        SplashPage.sName,
        LoginPage.sName,
        MainPage.sName,
        //...
      ];
      
      static init() {
        NavigatorManager.getInstance().streamController.stream.listen((state) {
            setupStatusBar(state[state.length - 1]);
        })
      }
    
      setupStatusBar(Route currentRoute) {
        if (lightRouteNameList.contains(currentRoute.settings.name)) {
          setLight();
        } else if (darkRoutNameList.contains(currentRoute.settings.name)) {
          setDart();
        }
      }
}
复制代码

完结,撒花🎉
相关文章
相关标签/搜索