路由的理解
移动端,前端中的路由指的是页面;例如:
- Android中activity,
- IOS中的ViewController
- Flutter 中的Route(页面的抽象)
flutter路由的关键对象
- Navigator:路由管理器,就是用来实现页面跳转的
- Route:页面的抽象,定义了路由线路
- Overlay:遮罩,Navigator的下层widget;Navigator包裹了Overlay;
flutter路由的实现分析
MaterialApp->WidgetsApp->Navigator
这是Navigator的widget层级包裹关系,也就是说Navigator在app启动时就 已经作为page(widegt)的上层;
#路由跳转的方法
Navigator.of(context)//1
.push(MaterialPageRoute(
builder: (context)=>MyHomePage()
));//2
注释1 通过context获取最上层的NavigatorState
注释2 调用 NavigatorState的push方法
#NavigatorState
Future<T> push<T extends Object>(Route<T> route) {
...
_history.add(_RouteEntry(route, initialState: _RouteLifecycle.push));//3
_flushHistoryUpdates();//4
...
_afterNavigation(route);
return route.popped;
}
注释3 对route对象做了一层包装,作为_RouteEntry对象,存放到_history列表
注释4 调用_flushHistoryUpdates方法,主要刷新_RouteEntry状态
overlay更新widget
void _flushHistoryUpdates({bool rearrangeOverlay = true}) {
...
int index = _history.length - 1;
_RouteEntry next;
_RouteEntry entry = _history[index];
_RouteEntry previous = index > 0 ? _history[index - 1] : null;
bool canRemoveOrAdd = false; // Whether there is a fully opaque route on top to silently remove or add route underneath.
Route<dynamic> poppedRoute; // The route that should trigger didPopNext on the top active route.
bool seenTopActiveRoute = false; // Whether we've seen the route that would get didPopNext.
final List<_RouteEntry> toBeDisposed = <_RouteEntry>[];
while (index >= 0) {
switch (entry.currentState) {
case _RouteLifecycle.add:
...
case _RouteLifecycle.push:
case _RouteLifecycle.pushReplace:
case _RouteLifecycle.replace:
assert(rearrangeOverlay);
entry.handlePush(//注释5
navigator: this,
previous: previous?.route,
previousPresent: _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate)?.route,
isNewFirst: next == null,
);
assert(entry.currentState != _RouteLifecycle.push);
assert(entry.currentState != _RouteLifecycle.pushReplace);
assert(entry.currentState != _RouteLifecycle.replace);
if (entry.currentState == _RouteLifecycle.idle) {
continue;
}
break;
...
index -= 1;
next = entry;
entry = previous;
previous = index > 0 ? _history[index - 1] : null;
}
...
if (rearrangeOverlay)//注释6
overlay?.rearrange(_allRouteOverlayEntries);
}
注释5 调用_RouteEntry的handlePush方法
void handlePush({ @required NavigatorState navigator, @required bool isNewFirst, @required Route<dynamic> previous, @required Route<dynamic> previousPresent }) {
...
final _RouteLifecycle previousState = currentState;
route._navigator = navigator;//5-1
route.install();//5-2
assert(route.overlayEntries.isNotEmpty);
if (currentState == _RouteLifecycle.push || currentState == _RouteLifecycle.pushReplace) {
final TickerFuture routeFuture = route.didPush();//5-3
currentState = _RouteLifecycle.pushing;
routeFuture.whenCompleteOrCancel(() {
if (currentState == _RouteLifecycle.pushing) {
currentState = _RouteLifecycle.idle;
assert(!navigator._debugLocked);
assert(() { navigator._debugLocked = true; return true; }());
navigator._flushHistoryUpdates();
assert(() { navigator._debugLocked = false; return true; }());
}
});
} else {
assert(currentState == _RouteLifecycle.replace);
route.didReplace(previous);
currentState = _RouteLifecycle.idle;
}
...
}
5-1:实现route对象 持有_navigator
5-2:初始化route对象的List<OverlayEntry> _overlayEntries 属性(OverlayEntry持有创建route对象时传入的widget)
5-3:返回一个Future对象 在完成push后 保障navigator获取焦点
接着看注释6,overlay是OverlayState的对象,_allRouteOverlayEntries是从_history中的_RouteEntry的Route对象的OverlayEntry对象 获取的
#OverlayState
void rearrange(Iterable<OverlayEntry> newEntries, { OverlayEntry below, OverlayEntry above }) {
final List<OverlayEntry> newEntriesList = newEntries is List<OverlayEntry> ? newEntries : newEntries.toList(growable: false);//6-1
...
if (newEntriesList.isEmpty)
return;
if (listEquals(_entries, newEntriesList))
return;
final LinkedHashSet<OverlayEntry> old = LinkedHashSet<OverlayEntry>.from(_entries);//6-2
for (final OverlayEntry entry in newEntriesList) {
entry._overlay ??= this;
}
setState(() {
_entries.clear();//6-3
_entries.addAll(newEntriesList);
old.removeAll(newEntriesList);
_entries.insertAll(_insertionIndex(below, above), old);//6-4
});
}
6-1:包装新的OverlayEntry对象(持有新的路由对应的widget)
6-2:包装原有的OverlayEntry对象
6-3:OverlayState 的_entries清空了列表数据,并把排序后的数据插入到列表;在原有的old列表 去除重复OverlayEntry对象
6-4:把在原有的old中的对象 插入到最后面
最后调用setState 重新build
重点
//Navigator 对应的 state
@override
Widget build(BuildContext context) {
// This list is filled backwards and then reversed below before
// it is added to the tree.
final List<Widget> children = <Widget>[];
bool onstage = true;
int onstageCount = 0;
for (int i = _entries.length - 1; i >= 0; i -= 1) {
final OverlayEntry entry = _entries[i];
if (onstage) {
onstageCount += 1;
children.add(_OverlayEntryWidget(
key: entry._key,
entry: entry,
));
if (entry.opaque)
onstage = false;
} else if (entry.maintainState) {
children.add(_OverlayEntryWidget(
key: entry._key,
entry: entry,
tickerEnabled: false,
));
}
}
return _Theatre(
skipCount: children.length - onstageCount,
children: children.reversed.toList(growable: false),
);
}
Overlay是一个有状态的widget,build的时候 把持有的全部OverlayEntry对象 包装成_OverlayEntryWidget,由_Theatre完成 渲染显示;
/// Special version of a [Stack], that doesn't layout and render the first
/// [skipCount] children.
///
/// The first [skipCount] children are considered "offstage".
class _Theatre extends MultiChildRenderObjectWidget {
...
}
_Theatre是一个特殊的widget,类似Stack;用来渲染指定范围的widget
总结
- Navigator.of(context)实际返回的是NavigatorState;
- pop,push等操作实际就是操作 List<_RouteEntry> _history = <_RouteEntry>[];
- _RouteEntry是Route的包装类
- Navigator组件 对overlay组件 做了一层包装,overlay控制页面的显示,
通过持有_Theatre舞台组件,类似Stack指定哪些页面widget要显示
Future<T> push<T extends Object>(Route<T> route) {
assert(!_debugLocked);
assert(() {
_debugLocked = true;
return true;
}());
assert(route != null);
assert(route._navigator == null);
_history.add(_RouteEntry(route, initialState: _RouteLifecycle.push));
_flushHistoryUpdates();
assert(() {
_debugLocked = false;
return true;
}());
_afterNavigation(route);
return route.popped;
}```
网友评论