一、单Navigator模式
首先看下NavigatorState build方法的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @override Widget build(BuildContext context) { assert(!_debugLocked); assert(_history.isNotEmpty); return HeroControllerScope.none( child: Listener( onPointerDown: _handlePointerDown, onPointerUp: _handlePointerUpOrCancel, onPointerCancel: _handlePointerUpOrCancel, child: AbsorbPointer( absorbing: false, child: FocusScope( node: focusScopeNode, autofocus: true, child: UnmanagedRestorationScope( bucket: bucket, child: Overlay( key: _overlayKey, initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const <OverlayEntry>[], ), ), ), ), ), ); } }
|
可以发现是靠Overlay来实现路由管理功能的。
以Navigator.push为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @optionalTypeArgs Future<T?> push<T extends Object?>(Route<T> route) { _pushEntry(_RouteEntry(route, initialState: _RouteLifecycle.push)); return route.popped; }
void _pushEntry(_RouteEntry entry) { .... _history.add(entry); _flushHistoryUpdates(); .... }
void _flushHistroyUpdates({bool rearrangeOverlay = true}){ entry.handlePush( navigator: this, previous: previous?.route, previousPresent: _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate)?.route, isNewFirst: next == null, ); if (rearrangeOverlay) { overlay?.rearrange(_allRouteOverlayEntries); } }
void handlePush({ required NavigatorState navigator, required bool isNewFirst, required Route<dynamic>? previous, required Route<dynamic>? previousPresent }) { .... route.install(); .... }
|
具体调用过程如下:
Navigator创建_RouteEntry
并添加到_history
列表里
遍历_history列表取出新添加的Entry并调用Route的install方法,创建OverlayEntry
实例
最后,调用OverlayState
的rearrange
方法把新创建的OverlayEntry
插入到Overlay里,完成路由页面的添加
Navigator其他api方法都是类似的原理,本质上都是通过管理_RouteEntry
列表来间接实现对Overlay的管理
二、FlutterBoost的多Navigator模式
FlutterBoost里的Widget结构为:
BoostContainerManager
|- Overlay
|- BoostNavigator
|- BoostNavigator
BoostNavigator是自定义的Navigator实例,每个原生容器(Activity、ViewController)都对应一个BoostNavigator实例并且被作为一个OverlayEntry插入到BoostContainerManager下的Overlay里。
下面是一些具体细节的剖析:
传递给MaterialApp的routes,onGenerateRoute参数怎么在这个模式下起作用呢?
在MaterialApp里有一个builder参数,它是一个函数,其中第一个Widget child
参数就是Navigator,它的onGenerateRoute参数是通过MaterialApp里的routes,home和onGenerateRoute等参数初始化的。
BoostContainerManager持有了这个Navigator实例,但是没有把它插入Widget Tree,而是用来生产BoostNavigator,从而保证诸如Navigator.pushNamed等官方api能正常使用。
FlutterBoost是怎么管理PopupRoute的?
在showDialog等方法中默认会有一个useRootNavigator的参数,顾名思义它会优先使用Widget树中最顶层的Navigator。而在FlutterBoost中RootNavigator被人为移除了,普通页面拿到的Navigator其实就是BoostNavigator实例,这样在单个原生容器的上下文中PageRoute和PopupRoute的管理就统一了起来。如果不这样做会有什么后果呢:
showDialog:使用RootNavigator
popDialog:必须要使用Navigator.of(context,rootNavigator:true),如果使用Navigator.of(context)那拿到的是BoostNavigator实例,是无法移除对话框的。