了解了navigator的大致原理,Navigator是需要MaterialApp支持的,在其内部才能使用。
Navigator也是一个Widget,他提供一个of方法使得子孙widget可以取到他的state。
static NavigatorState of(
BuildContext context, {
bool rootNavigator = false,
bool nullOk = false,
}) {...
: context.ancestorStateOfType(const TypeMatcher<NavigatorState>());
...
return navigator;
}
of方法中调用ancestorStateOfType方法,向上遍历父element,找到Navigator的element就把他的state返回,state中封装了各种push、pop方法
@override
State ancestorStateOfType(TypeMatcher matcher) {
assert(_debugCheckStateIsActiveForAncestorLookup());
Element ancestor = _parent;
while (ancestor != null) {
if (ancestor is StatefulElement && matcher.check(ancestor.state))
break;
ancestor = ancestor._parent;
}
final StatefulElement statefulAncestor = ancestor;
return statefulAncestor?.state;
}
为啥Navigator可以随意增删widget呢,其实他内部维护了一个用Overlay扩展的Stack,push粗糙的说其实就是往stack中配置多一个widget,然后rebuild。但是Stack是会把整个widgetList都进行绘制的,这样连续push页面后,会爆炸的。Overlay就是用来解决Stack的不足的,Overlay会把push的页面进行分类,是否需是否透明(如果透明,则下层widget也要参与绘制,反之不用)、要保存状态(如果不需要,那么在上层widget不透明的情况下,可以直接扔掉)。分类后,只有需要绘制的widget会按照顺序配置到Stack中rebuild。
以上是Navigator工作的简要描述。
通过了解Navigator的工作原理,可以看到,核心是Overlay,要自定义一个widget支持布局push、pop(类似安卓碎片的效果),那么完全可以把Overlay剥出来,Overlay本身支持of方法从子widget中获取他的state,他的state也提供了insert方法,可以插入一个widget。