Code前端首页关于Code前端联系我们

什么是导航器? Flutter 1.17 版本和性能改进

terry 2年前 (2023-09-22) 阅读数 73 #移动小程序

1。优化后的Navigator做了什么?

版本中最​​有趣的变化是:“打开新的模糊页面时,路径中的旧页面不会生成build

虽然build方法很轻量,但“不需要”时“不执行”当然更符合我们的预期,而这种优化的PR体现在›和 在两个文件中。改文件

  • 就是把RenderStack相关的逻辑改成共享静态方法getIntrinsicDimension和Potioned,其实就是共享堆栈 部分 的定制可能性由 Overlay 提供。
  • 编辑文件是当今的灵魂。 ? 、push等方法对应的逻辑在NavigatorState,车辆页面的”通过Overlay ,所以导航页面之间的管理逻辑在Overlay

    、什么是叠加?

    叠加您可能已经使用过它。在 Flutter 中,您可以使用 OverlayMaterialApp 添加全局悬浮控件。这是因为 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中有两个参数onstageoffstage‾‾,包括:‾‾ a 堆叠,已使用 显示 (growable: false ) ,即可见部分;

  • offstage是显示offstageChildren的列表,即缺失的部分;
    return _Theatre(
      onstage: Stack(
        fit: StackFit.expand,
        children: (growable: false),
      ),
      offstage: offstageChildren,
    );

很简单,因为如果有三个页面[A、B、C],那么:

  • C 应该在 平台上
  • 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

例如,程序默认启动时,页面A就是您看到的第一页。现在可以看到

  • _entries♽的Overlay的长度为2,即Overlay中列表的总长度为2;平台
  • 的长度为2,即当前可见的OverlayEntry为2;
  • child长度为0,即不可见OverlayEntry

Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

当我们打开B页面时,我们看到Overlay

  • _entries它的长度为4,即♽OOverlay额外的verlayEntry
添加到 ;

  • onstageChildren 的长度为 4,即当前可见的 OverlayEntry 的 4 个;
  • 在长度为0的平台之外,也就是说此时不存在OverlayEntry
  • Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    其实现在Overlay处于页面打开状态,即A页面仍然可见,B页面正在动画打开。.长度,即当前可见的OverlayEntry 变为 2; Children阶段中

  • 的长度为1,这意味着当前有一个OverlayEntry
  • Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    此时B页面其实已经打开了,所以返回了onstageChildren,长度为2,即两个OverlayEntry与页面对应。而A页缺失,因此A页被放置在平台外的

    为什么A的OverlayEntry只放在舞台外?这些事会晚一些讨论。

    Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    如下图,当你打开C页时,你会发现你已经通过了同样的方式:

    • _entries长度变为6;
    • 上台 长度先变成4,然后又变回2,因为开场涉及B、C两页,开场结束后只剩下C一页;
    • 从平台长度为1,然后变成2,因为一开始只缺少A,最后A和B都缺少;

    Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    然后你会看到每次打开页面时:

    • 都会将_text插入到两个OverlayEntry;
    • 会先到 在平台上 页面打开状态,长度为4;
    • 变成onstage长度为2的页面完成状态,低于So的页面隐藏在offstageChildren中;
        return _Theatre(
          onstage: Stack(
            fit: StackFit.expand,
            children: (growable: false),
          ),
          offstage: offstageChildren,
        );
    

    ,Overlay和Route

    为什么有两个 OverlayEntry 包含在 _entries 中?

    这与有关。例如,默认需要使用Navigator来打开新页面。生成MaterialPageRouteOverlayEntry 这是主要类之一ModalRoute 已完成。

    ModalRoutecreateOverlayEntries方法中,插入♽_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?

    逻辑上,根据前面三页[A,B,C]的例子,‽_entry和BC中有6个OverlayEntry

    ,那么就看不到了。把蒙版带到B页和C页不是浪费吗?

    从代码层面解释,当_entriesfor 循环时:

    • 遇到›♽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 将会是 将会是 也会进入,所以当进入时, 也会进入是台下的孩子

    Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    那么不透明 集在哪里?

    opaque的安装过程如下。在TransitionRouteMaterialPageRoute中可以看到Masked的开头MaterialPageRoute,可以看到Masked的开头ed 参数在 ♽ 在页面

        return _Theatre(
          onstage: Stack(
            fit: StackFit.expand,
            children: (growable: false),
          ),
          offstage: offstageChildren,
        );
    

    @override bool 变得不透明 => true;

    PopupRoutePoopaque 这是假。通常背景透明,需要与上一页一起显示。

     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失踪后;
  • 作为附加输入,当 OverlayEntry 相关时,与 相关时传递的 OverlayEntry 相同,例如: 结束_history(堆栈路由页面)。

    3。新版本中覆盖

    那么为什么在build之前打开新页面时旧页面会被杀死? 这里其实有两点很重要:

    • OverlayEntry有一个GlobalKey❀代表用户的唯一性;
    • OverlayEntry
        return _Theatre(
          onstage: Stack(
            fit: StackFit.expand,
            children: (growable: false),
          ),
          offstage: offstageChildren,
        );
    

    _剧院中的 中,舞台上♽ 将会有从开始的步骤;

    ,为什么要构建

    ,因为覆盖中的覆盖条目将被更改♽En♽♽ 在内用于功能,GlobalKeyOverlayEntry将自动被_OverlayEntry使用,当 G使用 Widget,则对应的 Element 将为“全局”。

    Element执行inflateWidget时,会判断♽GlobalKey

    的值是否会调用_retakeInactiveElement 。方法返回“现有的" Element对象,因此Element在其他地方被“复用”,这个过程是‽原本从中移除并添加到新的 家长

    此步骤将生成Element

    updateupdate 和 _OverlayEntry. 本身 StatefulWidget ,所以对应的 StatefulElement update 会生成 rebuild

    、为什么不重建

    ?为避免每次打开页面时出现旧页面重建的情况,请取消舞台上的_Theatre ,用符号代替skipCountchild

    _TheatreRenderObjectWidget 更改为 是 RenderObjectWidget,然后使用 RenderObjectWidget在_RenderTheatreRenderStack 共享容量计划。

      @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 相同 Overlay

    Overlay

    ,与元素相同
    ,代替之前的控制,需要在Stack和平台外的

        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也会发生变化。也证实了页面打开过程中和关闭后的逻辑完全没有变化。

    Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    从结果来看,这个改变确实提升了性能。当然,这种改进主要适用于不清晰的页面。如果是像PopModal之类的透明页面导致的,你仍然需要重建

    Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    4。其他改进

    Metal 是一个低调的编程接口,类似于 iOS 上的OpenGL ES,可以通过 API 直接与 iOS 设备上的 GPU 配合使用。

    从一开始,Flutter 就会在 iOS 上支持 Metal 的设备上使用Metal,所以根据官方数据,可以提升 50% 的性能。查看更多:https://github.com/flutter/flutter/wiki/Metal-on-iOS-FAQ

    Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    由于 Android 上 Dart VM 的优化,其大小可以减少约 100 倍。

    改进了多图像加载的处理,在快速导航时可以提高更好的性能(通过延迟IO线程环境的清理),可以节省原来70%的成本。记忆。

    Navigator 优化了什么?Flutter 1.17 导航解密和性能提升

    版权声明

    本文仅代表作者观点,不代表Code前端网立场。
    本文系作者Code前端网发表,如需转载,请注明页面地址。

    发表评论:

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

    热门