默认状况下,一次路由,由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,
);
}
复制代码