默認狀況下,一次路由,由Navigator(route管理類)發起,Overlay(Navigator的子節點,用來掛載route的界面)切換Route(別名、界面管理類)所攜帶的界面。bash
Navigator一個StatefulWidget嵌套在MaterialApp內部,其狀態類NavigatorState(class NavigatorState extends State with TickerProviderStateMixin)能夠在路由界面內,經過Navigator.of(context)獲取。
一個標準的路由實現ide
Navigator.push(context, new MaterialPageRoute(builder: (_) {
return MyHomePage();
}));
複製代碼
push 內部動畫
Future<T> push<T extends Object>(Route<T> route) {
route.install(_currentOverlayEntry);
// 路由表
_history.add(route);
// 路由動做開始,(設置焦點,開始動畫)
route.didPush();
return route.popped;
}
複製代碼
1.先初始化動畫相關
2. 會初始化兩個界面,一個是 _modalBarrier黑色蒙層,和咱們須要路由的界面 由 _buildModalScope方法返回ui
Iterable<OverlayEntry> createOverlayEntries() sync* {
yield _modalBarrier = OverlayEntry(builder: _buildModalBarrier);
yield OverlayEntry(builder: _buildModalScope, maintainState: maintainState);
}
複製代碼
_buildModalScope 返回的界面this
_ModalScopeStatus(
...
child: AnimatedBuilder(
builder: (BuildContext context, Widget child) {
// 界面切換動畫
return widget.route.buildTransitions(
context,
widget.route.animation,
widget.route.secondaryAnimation,
);
},
child: _page ??= RepaintBoundary(
child: Builder(
builder: (BuildContext context) {
// 咱們須要路由的界面
return widget.route.buildPage(
context,
widget.route.animation,
widget.route.secondaryAnimation,
);
},
),
),
)
複製代碼
3.調用navigator.overlay.insertAll()插入第二部初始化的界面spa
void insertAll(Iterable<OverlayEntry> entries, { OverlayEntry above }) {
if (entries.isEmpty)
return;
for (OverlayEntry entry in entries) {
assert(entry._overlay == null);
entry._overlay = this;
}
// 更新界面
setState(() {
final int index = above == null ? _entries.length : _entries.indexOf(above) + 1;
_entries.insertAll(index, entries);
});
}
複製代碼
Overlay 嵌套Stack,經過棧來管理界面code
Widget build(BuildContext context) {
...
return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: onstageChildren.reversed.toList(growable: false),
),
offstage: offstageChildren,
);
}
複製代碼