Routing section of actual combat record of Flutter online project

  • 2021-11-13 02:34:16
  • OfStack

1. Application scenarios

Often encountered in development

What should I do if I can't get context when the route jumps? eg: token invalidation/remote login jump login page. What should I do if I can't get the current route name? eg: Click push to push and jump to specify the route. If it is already on the current page, replace will be used, and if it is not, push will be used. Register to listen to route jumps, do something you want to do, eg: Different routes, display different status bar colors. Wait...

2. Solutions

Solutions:

The routes attribute of MaterialApp assigns the routing array, and the navigatorObservers attribute assigns the routing listener NavigatorManager. didPush/didReplace/didPop/didRemove of NavigatorObserver is implemented in NavigatorManager and recorded in the routing stack List _mRoutes. Jump the route recorded in real time, send a broadcast with stream, and register where you need it.

3. Concrete realization

main.dart


MaterialApp(
 navigatorObservers: [NavigatorManager.getInstance()],
 routes: NavigatorManager.configRoutes,
 ...
)

navigator_manager.dart


class NavigatorManager extends NavigatorObserver {
 /*  Configure routes */
 static Map<String, WidgetBuilder> configRoutes = {
 PackageInfoPage.sName: (context) =>
 SplashPage.sName: (context) => SplashPage(),
 LoginPage.sName: (context) => SplashPage()),
 MainPage.sName: (context) => SplashPage(),
 //...
 }
 //  Current routing stack 
 static List<Route> _mRoutes;
 List<Route> get routes => _mRoutes;
 //  Current route 
 Route get currentRoute => _mRoutes[_mRoutes.length - 1];
 // stream Correlation 
 static StreamController _streamController;
 StreamController get streamController=> _streamController;
 //  Used to route jumps 
 static NavigatorState navigator;
 
 /*  Single example gives NavigatorManager */
 static NavigatorManager navigatorManager;
 static NavigatorManager getInstance() {
 if (navigatorManager == null) {
  navigatorManager = new NavigatorManager();
  _streamController = StreamController.broadcast();
 }
 return navigatorManager;
 }
 
 // replace  Page 
 pushReplacementNamed(String routeName, [WidgetBuilder builder]) {
 return navigator.pushReplacement(
  CupertinoPageRoute(
  builder: builder ?? configRoutes[routeName],
  settings: RouteSettings(name: routeName),
  ),
 );
 }
 
 // push  Page 
 pushNamed(String routeName, [WidgetBuilder builder]) {
 return navigator.push(
  CupertinoPageRoute(
  builder: builder ?? configRoutes[routeName],
  settings: RouteSettings(name: routeName),
  ),
 );
 }
 
 // pop  Page 
 pop<T extends Object>([T result]) {
 navigator.pop(result);
 }
 
 // push1 Pages,   Remove all pages below this page 
 pushNamedAndRemoveUntil(String newRouteName) {
 return navigator.pushNamedAndRemoveUntil(newRouteName, (Route<dynamic> route) => false);
 }
 
 //  When the call Navigator.push Time callback 
 @override
 void didPush(Route route, Route previousRoute) {
 super.didPush(route, previousRoute);
 if (_mRoutes == null) {
  _mRoutes = new List<Route>();
 }
 //  Filter the tune here push Is dialog The situation of 
 if (route is CupertinoPageRoute || route is MaterialPageRoute) {
  _mRoutes.add(route);
  routeObserver();
 }
 }
 
 //  When the call Navigator.replace Time callback 
 @override
 void didReplace({Route newRoute, Route oldRoute}) {
 super.didReplace();
 if (newRoute is CupertinoPageRoute || newRoute is MaterialPageRoute) {
  _mRoutes.remove(oldRoute);
  _mRoutes.add(newRoute);
  routeObserver();
 }
 }
 
 //  When the call Navigator.pop Time callback 
 @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, '&& Routing stack &&');
 LogUtil.i(sName, _mRoutes);
 LogUtil.i(sName, '&& Current route &&');
 LogUtil.i(sName, _mRoutes[_mRoutes.length - 1]);
 //  Of the current page navigator Which is used to route jumps 
 navigator = _mRoutes[_mRoutes.length - 1].navigator;
 streamController.sink.add(_mRoutes);
 }
}

4. How to use

token failure jump


case 401:
  ToastUtil.showRed(' Log-in invalidation , Please log in again ');
  UserDao.clearAll();
  NavigatorManager.getInstance().pushNamedAndRemoveUntil(LoginPage.sName);
  break;

Click push to push the jump


static jumpPage(String pageName, [WidgetBuilder builder]) {
  String currentRouteName = NavigatorManager.getInstance().currentRoute.settings.name;
  //  If you are not logged in, do not jump 
  if (NavigatorManager.getInstance().routes[0].settings.name != MainPage.sName) {
   return;
  }

  //  If it is already the current page, replace
  if (currentRouteName == pageName) {
   NavigatorManager.getInstance().pushReplacementNamed(pageName, builder);
  } else {
   NavigatorManager.getInstance().pushNamed(pageName, builder);
  }
}

Listen for routes to change status bar color


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();
    }
   }
}

End, sprinkle flowers in


Related articles: