什么是导航器? 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
不会进入平台,即不会显示;页面
-
OverlayEntry
maintainState
将会是将会是
也会进入,所以当进入时, 也会进入是
台下的孩子
;
那么不透明
集在哪里?
@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前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。