【问题标题】:Flutter performance: Padding on every widget vs padding on top level listviewFlutter 性能:每个小部件上的填充与顶级列表视图上的填充
【发布时间】:2021-11-04 12:46:52
【问题描述】:

场景 1:一个 ListView 有 10 个子小部件,每个小部件的水平对称内边距为 20.0。

return ListView(
  children: <Widget>[
    Padding(
      padding: const EdgeInsets.symmetric(horizontal: 20.0),
      child: Widget1),
    Padding(
      padding: const EdgeInsets.symmetric(horizontal: 20.0),
      child: Widget2),
    // ...8 more like that...
  ],);

场景 2: ListView 有 10 个没有任何填充的子小部件。而是将 20.0 的对称水平填充应用于 ListView 本身。

return Padding(
  padding: const EdgeInsets.symmetric(horizontal: 20.0),
  child: ListView(
    children: <Widget>[
      Widget1,
      Widget2,
    // ...8 more like that...
  ],),);

在场景 1 中是否会有更多开销(在 UI 线程中)?还是会几乎保持不变。

PS:考虑到每个小部件都是不同的,ListView.builder 不是一个选项。

【问题讨论】:

    标签: flutter flutter-layout


    【解决方案1】:

    根据我的观点,您应该使用列表视图的填充属性:-

    return ListView(
      padding: const EdgeInsets.symmetric(horizontal: 20.0),
      children: <Widget>[
          Widget1,
          Widget2,
        // ...8 more like that...
      ],
    );
    

    在第一种情况下,假设您有 10 个孩子,那么将呈现 10*2=20 个小部件,因为它们上存在填充,因此乘以 2。而在第二种情况下,只会呈现 11 个。但我分享的示例将只呈现 10 个小部件。

    Ps:-忽略了listview小部件的计数(如果想考虑那么只需将所有情况都加1)。

    【讨论】:

    • 如果我错了,请纠正我,但有时在跟踪错误时我注意到在 Container 小部件的情况下,AlignmentPadding 等属性转换为 widgets 并加起来到小部件树。 ListView也是这样吗?
    • 如果你查看 ListView 的原生代码,你可以看到它扩展了 BoxScrollView-->ScrollView-->StatelessWidget。所以,我想添加一件事,每当您将小部件声明为无状态时,即使小部件的子级包含 n 个小部件,它也会被视为单个小部件。因此,我们可以说 padding 不会被视为一个新的小部件。
    【解决方案2】:

    这里所有的答案都很好,但要说一件事。

    // 最好是第一个

    场景 2:显然,更少的工作量意味着代码的性能更高。在这里,我们直接渲染了2 + 10 = 12 小部件,因此每当渲染小部件时,flutter 的 Skia 引擎会渲染 12 个组件。 现在,如果您深入研究状态管理或小部件更新,这意味着每次连续运行构建方法时,树都会从根部重新构建,您只渲染 12 个组件。

    场景 1:这里的性能问题是它在构建方法的一次运行中渲染 1 + ( 2 * 10 ) = 21 小部件。所以现在如果我们从需要重建树的角度来看,它必须做更多的工作来移除比场景 2 多 9 个小部件并再次构建多 9 个小部件。

    PS。您还可以使用 const 关键字优化一些不需要一次又一次重建的静态小部件。

    我还想补充一点,这并不是大幅提升性能,我的意思是您可能也无法使用开发工具来验证提升。

    【讨论】:

      【解决方案3】:

      一般来说,差异是如此微不足道,以至于它不应该成为您的决定因素。相反,您应该确定哪种方法对您的业务逻辑更有意义,或提高代码的可读性,或两者兼而有之。

      严格来说,直接在 ListView 中添加 padding 会稍微提高性能,因为需要的计算量会稍微少一些。此外,值得注意的是,Padding 小部件实际上不会“绘制一个不可见的容器,绘制一些不可见的间隙,然后在中间绘制它的子级”——这不是它的工作原理。实际上,它的效率要高得多:简而言之,小部件在一次 O(n) 操作中布局,只需遍历小部件树一次。向下时,它通过父母的约束,向上时,它通过孩子的尺寸。对于Padding 小部件,它只是在向下传递时修改了父级的约束,因此几乎不需要担心开销。

      还值得注意的是ListView 具有padding 属性,因此直接使用它是您没有提到的第三个选项。请注意,ListView 的填充属性与使用 Padding 小部件包装它的行为也不相同,您可能也需要担心 SafeArea。您可以通过一些实验轻松解决这些问题。同样,所有 3 种方法的性能成本都很低,您应该选择对您的业务逻辑最有意义的一种。

      【讨论】:

        【解决方案4】:

        第一种情况更好,因为您的小部件树更小

        【讨论】:

        • 你确定吗??
        • 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。
        猜你喜欢
        • 2021-07-22
        • 1970-01-01
        • 2021-01-28
        • 2020-11-24
        • 1970-01-01
        • 2014-01-05
        • 2014-04-13
        • 2016-12-01
        • 1970-01-01
        相关资源
        最近更新 更多