什么是导航器? Flutter 1.17 版本和性能改进
1。优化后的Navigator做了什么?
版本中最有趣的变化是:“打开新的模糊页面时,路径中的旧页面不会生成build”。
虽然build方法很轻量,但“不需要”时“不执行”当然更符合我们的预期,而这种优化的PR体现在›和 在两个文件中。改文件
就是把RenderStack相关的逻辑改成共享静态方法getIntrinsicDimension和Potioned,其实就是共享堆栈 部分 的定制可能性由Overlay提供。编辑文件是当今的灵魂。 ? 、push等方法对应的逻辑在NavigatorState,车辆页面的”通过Overlay ,所以导航页面之间的管理逻辑在Overlay。、什么是叠加?
叠加您可能已经使用过它。在 Flutter 中,您可以使用Overlay为MaterialApp添加全局悬浮控件。这是因为Overlay与Stack控制层次结构类似,但可以使用 ♽ ♽独立管理内部控制显示,例如,您可以输入
OverlayEntry使用添加图层,然后使用OverlayEntry♽♽♽♽♽♽♽♽ ♽♽♽♽♽♽♽ ♽♽♽♽♽♽♽♽♽♽♽显示时会调用 ♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽♽》 ,所以需要的布局结果为显示。var overlayState = (context); var _overlayEntry = new OverlayEntry(builder: (context) { return new Material( color: Colors.transparent, child: Container( child: Text( "${} ${} ${} ${}", style: TextStyle(color: Colors.white, fontSize: 10), ), ), ); }); (_overlayEntry);、如何将浏览器应用到Overlay?
实际上用于
Navigator。默认为Overlay输入两个OverlayEntry。为什么有两个稍后会展示。
而
overlay中,list _entries的显示逻辑是由_theatre完成的。在_Theatre中有两个参数onstage和offstage‾‾,包括:‾‾ a堆叠,已使用 显示(growable: false ),即可见部分;offstage是显示offstageChildren的列表,即缺失的部分;
return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: (growable: false),
),
offstage: offstageChildren,
);
很简单,因为如果有三个页面[A、B、C],那么:
- C 应该在
平台上; - A 和 B 应位于
外侧。
显然是插入到中的 例如,程序默认启动时,页面A就是您看到的第一页。现在可以看到 当我们打开B页面时,我们看到OverlayEntry添加到 ; 中的 return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: (growable: false),
),
offstage: offstageChildren,
);
return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: (growable: false),
),
offstage: offstageChildren,
);
Overlay中OverlayEntry 方法,以及A、B、C 默认有两页。 OverlayEntry,即[A,B,C]应该有6个OverlayEntry。_entries♽的上Overlay的长度为2,即Overlay中列表的总长度为2;平台的长度为2,即当前可见的OverlayEntry为2; child长度为0,即不可见OverlayEntry; ![]()
Overlay:_entries它的长度为4,即♽OOverlay额外的verlayEntry
onstageChildren 的长度为 4,即当前可见的 OverlayEntry 的 4 个; 在长度为0的平台之外,也就是说此时不存在OverlayEntry。 ![]()
其实现在Overlay处于页面打开状态,即A页面仍然可见,B页面正在动画打开。.长度,即当前可见的OverlayEntry 变为 2; Children阶段中
的长度为1,这意味着当前有一个OverlayEntry。 ![]()
此时B页面其实已经打开了,所以返回了 为什么A的 如下图,当你打开C页时,你会发现你已经通过了同样的方式: 然后你会看到每次打开页面时: ,Overlay和Route 为什么有两个 这与 在 所以默认打开一个页面时,会有两个 所以有两页 逻辑上,根据前面三页[A,B,C]的例子,‽_entry和BC中有6个OverlayEntryonstageChildren,长度为2,即两个OverlayEntry与页面对应。而A页缺失,因此A页被放置在平台外的,那么就看不到了。把蒙版带到B页和C页不是浪费吗? 。 OverlayEntry只放在舞台外?这些事会晚一些讨论。![]()
_entries长度变为6; 上台 长度先变成4,然后又变回2,因为开场涉及B、C两页,开场结束后只剩下C一页; 从平台长度为1,然后变成2,因为一开始只缺少A,最后A和B都缺少; ![]()
![]()
_text插入到两个OverlayEntry; 在平台上 页面打开状态,长度为4; onstage长度为2的页面完成状态,低于So的页面隐藏在offstageChildren中; return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: (growable: false),
),
offstage: offstageChildren,
);
OverlayEntry 包含在 ? _entries 中? 路有关。例如,默认需要使用Navigator来打开新页面。生成MaterialPageRoute。 OverlayEntry 这是主要类之一ModalRoute 已完成。 ModalRoute的createOverlayEntries方法中,插入♽_build ModalRoute _buildModalScope创建OverlayEntry,其中:_buildModalBarrier 通常会创建一个遮罩; _buildModalScope 创建OverlayEntry,打开页面; OverlayEntry ,一个是叠加层,另一个是页面。 @override
Iterable<OverlayEntry> createOverlayEntries() sync* {
yield _modalBarrier = OverlayEntry(builder: _buildModalBarrier);
yield OverlayEntry(builder: _buildModalScope, maintainState: maintainState);
}
OverlayEntry,但是为什么每有一个Children,添加到的数字就会增加1?
从代码层面解释,当_entries转for 循环时:
遇到›♽ture 时间,跟进OverlayEntry无法访问后台;在Offstage中,只有right会添加到阵容中;
@override
Widget build(BuildContext context) {
final List<Widget> onstageChildren = <Widget>[];
final List<Widget> offstageChildren = <Widget>[];
bool onstage = true;
for (int i = _entries.length - 1; i >= 0; i -= 1) {
final OverlayEntry entry = _entries[i];
if (onstage) {
(_OverlayEntry(entry));
if ()
onstage = false;
} else if () {
(TickerMode(enabled: false, child: _OverlayEntry(entry)));
}
}
return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: (growable: false),
),
offstage: offstageChildren,
);
}
并且在 OverlayEntry 中:
不透明指示是否OverlayEntry ♽♽ 整个 叠加,就是全覆盖,不清楚。保持状态意味着这个OverlayEntry必须添加到_Theater。
然后你会看到,当页面完全打开时,que中的前两个OverlayEntry:
- mask
OverlayEntry♽‽♽将被设置为 true,所以下一个上的OverlayEntry不会进入平台,即不会显示;页面 -
OverlayEntrymaintainState将会是将会是也会进入,所以当进入时, 也会进入是台下的孩子;
![]()
那么不透明 集在哪里?
@override bool 变得不透明 => true;opaque的安装过程如下。在TransitionRoute的MaterialPageRoute中可以看到Masked的开头MaterialPageRoute,可以看到Masked的开头ed 参数在 ♽ 在页面 return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: (growable: false),
),
offstage: offstageChildren,
);
在 PopupRoute 在 Poopaque 这是假。通常背景透明,需要与上一页一起显示。
void _handleStatusChanged(AnimationStatus status) {
switch (status) {
case AnimationStatus.completed:
if ()
overlayEntries.first.opaque = opaque;
break;
case AnimationStatus.forward:
case AnimationStatus.reverse:
if ()
overlayEntries.first.opaque = false;
break;
case AnimationStatus.dismissed:
if (!isActive) {
(this);
assert();
}
break;
}
changedInternalState();
}
这里解释一下页面打开时Overlay的工作逻辑。默认情况下:
- 每个页面打开时,会在
Overlay中插入两个OverlayEntry; - 在打开过程中,
onstageChildren为4,因为当前两个页面是混合的; - 开场后,
中的2个在舞台上的孩子,因为不透明的放在
return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: (growable: false),
),
offstage: offstageChildren,
);
上,并跟随从远处可见的页面;
OverlayEntry♽♽♽♽ 上具有 保持状态 至 true 将进入 ❀ Child失踪后; 作为附加输入,当 那么为什么在 _剧院中的 ,因为 当 此步骤将生成Element ?为避免每次打开页面时出现旧页面 和 目前与 列表之间进行切换 在 最后如下图所示,打开页面后, 从结果来看,这个改变确实提升了性能。当然,这种改进主要适用于不清晰的页面。如果是像 从一开始,Flutter 就会在 iOS 上支持 由于 Android 上 Dart VM 的优化,其大小可以减少约 100 倍。 改进了多图像加载的处理,在快速导航时可以提高更好的性能(通过延迟IO线程环境的清理),可以节省原来70%的成本。记忆。 与 OverlayEntry 相关时,与 相关时传递的 OverlayEntry 相同,例如: 结束_history(堆栈路由页面)。 3。新版本中覆盖
build之前打开新页面时旧页面会被杀死? 这里其实有两点很重要:OverlayEntry有一个GlobalKey❀代表用户的唯一性; OverlayEntry return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: (growable: false),
),
offstage: offstageChildren,
);
中,舞台上♽ 将会有从开始的步骤; ,为什么要构建
覆盖中的覆盖条目将被更改♽En♽♽ 在内用于功能,GlobalKey在OverlayEntry将自动被_OverlayEntry使用,当 G使用 Widget的,则对应的 的值是否会调用Element 将为“全局”。Element执行inflateWidget时,会判断♽GlobalKey_retakeInactiveElement 。方法返回“现有的" 。 Element对象,因此Element在其他地方被“复用”,这个过程是‽原本父从中移除并添加到新的 家长update和的update 和 _OverlayEntry. 本身 StatefulWidget ,所以对应的 StatefulElement 的 update 会生成 rebuild。 、为什么不重建
重建的情况,请取消舞台上的_Theatre ,代替之前的控制,需要在 ,与元素相同 ♽ ,用符号代替skipCount 和 child。 _Theatre 从 RenderObjectWidget 更改为 是 RenderObjectWidget Overlay,然后使用 RenderObjectWidget在_RenderTheatre。RenderStack 共享容量计划。 @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;
(_OverlayEntryWidget(
key: entry._key,
entry: entry,
));
if ()
onstage = false;
} else if () {
(_OverlayEntryWidget(
key: entry._key,
entry: entry,
tickerEnabled: false,
));
}
}
return _Theatre(
skipCount: children.length - onstageCount,
children: children.reversed.toList(growable: false),
);
}
Overlay 中的_entries 相同 OverlayStack和平台外的 return _Theatre(
onstage: Stack(
fit: StackFit.expand,
children: (growable: false),
),
offstage: offstageChildren,
);
_剧院 将两个数字合并为一个child,并将除♽♽ skipCount 之外的部分放在舞台上 ,获取 _firstOnstageChild在布局设计期间,当children更改时,MultiChild元素配方includeChildRenderObject否则它将“包含”在上一页上,因此重建 将会不能建立在上一页上。 RenderBox get _firstOnstageChild {
if (skipCount == ) {
return null;
}
RenderBox child = super.firstChild;
for (int toSkip = skipCount; toSkip > 0; toSkip--) {
final StackParentData childParentData = child.parentData as StackParentData;
child = childParentData.nextSibling;
assert(child != null);
}
return child;
}
RenderBox get _lastOnstageChild => skipCount == ? null : lastChild;
child会出现从4到3的变化,onstageCount也会发生变化。也证实了页面打开过程中和关闭后的逻辑完全没有变化。 ![]()
![]()
PopModal之类的透明页面导致的,你仍然需要重建。 ![]()
4。其他改进
Metal 是一个低调的编程接口,类似于 iOS 上的OpenGL ES,可以通过 API 直接与 iOS 设备上的 GPU 配合使用。 Metal 的设备上使用Metal,所以根据官方数据,可以提升 50% 的性能。查看更多:https://github.com/flutter/flutter/wiki/Metal-on-iOS-FAQ![]()
![]()
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网



发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。