路由的理解
移動端,前端中的路由指的是頁面;例如:
- Android中activity,
- IOS中的ViewController
- Flutter 中的Route(頁面的抽象)
flutter路由的關(guān)鍵對象
- Navigator:路由管理器,就是用來實現(xiàn)頁面跳轉(zhuǎn)的
- Route:頁面的抽象,定義了路由線路
- Overlay:遮罩,Navigator的下層widget;Navigator包裹了Overlay;
flutter路由的實現(xiàn)分析
MaterialApp->WidgetsApp->Navigator
這是Navigator的widget層級包裹關(guān)系,也就是說Navigator在app啟動時就 已經(jīng)作為page(widegt)的上層;
#路由跳轉(zhuǎn)的方法
Navigator.of(context)//1
.push(MaterialPageRoute(
builder: (context)=>MyHomePage()
));//2
注釋1 通過context獲取最上層的NavigatorState
注釋2 調(diào)用 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 調(diào)用_flushHistoryUpdates方法,主要刷新_RouteEntry狀態(tài)
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 調(diào)用_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:實現(xiàn)route對象 持有_navigator
5-2:初始化route對象的List<OverlayEntry> _overlayEntries 屬性(OverlayEntry持有創(chuàng)建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對象(持有新的路由對應(yīng)的widget)
6-2:包裝原有的OverlayEntry對象
6-3:OverlayState 的_entries清空了列表數(shù)據(jù),并把排序后的數(shù)據(jù)插入到列表;在原有的old列表 去除重復(fù)OverlayEntry對象
6-4:把在原有的old中的對象 插入到最后面
最后調(diào)用setState 重新build
重點
//Navigator 對應(yīng)的 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是一個有狀態(tài)的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
總結(jié)
- 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;
}```