【问题标题】:Understanding Flutter Render Engine了解 Flutter 渲染引擎
【发布时间】:2019-04-27 07:45:01
【问题描述】:

关于如何更新ListView 的文档here 说:

在 Flutter 中,如果您要更新一个 setState(),你会很快看到你的数据没有改变 视觉上。这是因为当调用 setState() 时,Flutter 渲染引擎查看小部件树以查看是否有任何内容 改变了。当它到达您的 ListView 时,它会执行 == 检查,然后 确定两个 ListView 相同。什么也没有变, 所以不需要更新。

要更新 ListView 的简单方法,请在 setState(),并将旧列表中的数据复制到新列表中。

在这种情况下,我不明白渲染引擎如何确定小部件树中是否有任何更改。

AFAICS,我们关心调用setState,它将State 对象标记为脏并要求它重建。一旦它重建,就会有一个新的ListView,不是吗?那么== 怎么会说它是同一个对象呢?

另外,新的List 将在State 对象内部,Flutter 引擎会比较State 对象内的所有对象吗?我以为它只比较了Widget 树。

所以,基本上我不明白渲染引擎如何决定要更新什么以及要忽略什么,因为我看不到创建新的List 是如何将任何信息发送到渲染引擎的,因为文档说渲染引擎只是寻找一个新的ListView... AFAIK 一个新的List 不会创建一个新的ListView

【问题讨论】:

  • 这是我在阅读文档时遇到的一个理论问题。不涉及实际代码

标签: flutter flutter-layout


【解决方案1】:

Flutter 不仅仅由 Widgets 组成。

当您调用setState 时,您将Widget 标记为脏。但是这个 Widget 实际上并不是你在屏幕上呈现的。 存在用于创建/改变 RenderObjects 的小部件;正是这些 RenderObjects 在屏幕上绘制您的内容。

RenderObjects 和 Widgets 之间的链接是使用一种新的 Widget 完成的:RenderObjectWidget(如LeafRenderObjectWidget

Flutter 提供的大部分小部件在某种程度上都是一个 RenderObjectWidget,包括 ListView。

一个典型的 RenderObjectWidget 示例如下:

class MyWidget extends LeafRenderObjectWidget {
  final String title;

  MyWidget(this.title);

  @override
  MyRenderObject createRenderObject(BuildContext context) {
    return new MyRenderObject()
      ..title = title;
  }

  @override
    void updateRenderObject(BuildContext context, MyRenderObject renderObject) {
      renderObject
        ..title = title;
    }
}

此示例使用小部件来创建/更新 RenderObject。但是,通知框架有一些东西需要重新绘制是不够的。

要重新绘制 RenderObject,必须在所需的 renderObject 上调用 markNeedsPaintmarkNeedsLayout

这通常由 RenderObject 本身使用自定义字段设置器以这种方式完成:

class MyRenderObject extends RenderBox {
  String _title;
  String get title => _title;
  set title(String value) {
    if (value != _title) {
      markNeedsLayout();
      _title = value;
    }
  }
}

注意if (value != previous)

此检查可确保当小部件在不更改任何内容的情况下重新构建时,Flutter 不会重新布局/重新绘制任何内容。

正是由于这种确切的条件,突变 ListMap 不会使 ListView 重新呈现。它基本上有以下几点:

List<Widget> _children;
List<Widget> get children => _children;
set children(List<Widget> value) {
  if (value != _children) {
    markNeedsLayout();
    _children = value;
  }
}

但这意味着如果您改变列表而不是创建一个新列表,RenderObject 将不会被标记为需要重新布局/重绘。因此不会有任何视觉更新。

【讨论】:

  • 有趣...然后文档是错误的,当它说渲染引擎检查 ListView 对象中的相等性时...实际上ListView 检查其内容中的相等性...同样有趣的是看到RenderObject 上的突变,Flutter 文档谈到了很多关于不变性,我认为它都是不可变的
  • 两者都有,children 检查是后面的步骤。如果您返回相同的 ListView 实例,它甚至不会到达 children 检查并在之前中止。
  • RenderObject 是可变的很好,你几乎不必自己创建一个。 Flutter 处理可变性,因此我们不必这样做。
  • “您返回相同的ListView”是什么意思? AFAIK,我只在 build 方法中创建一个新的 ListView,并且由于不可变性,它总是一个新的
  • 抱歉给我带来了困惑,这些对我来说都是新信息......如果有一篇文章详细解释(至少我没有找到)会很高兴setState()触发了哪些行为,深入,因为你给我解释的越多,我的疑惑就越多哈哈哈
猜你喜欢
  • 2011-05-05
  • 2013-06-08
  • 2014-05-03
  • 1970-01-01
  • 2017-05-31
  • 2011-11-19
  • 1970-01-01
  • 2022-01-10
  • 2021-05-18
相关资源
最近更新 更多