了解Flutter渲染引擎

时间:2018-11-25 13:30:27

标签: flutter flutter-layout

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

  

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

     

对于更新ListView的简单方法,请在其中创建一个新List   setState(),然后将数据从旧列表复制到新列表。

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

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

此外,新的List将位于State对象的内部,Flutter引擎是否会比较State对象内部的所有对象?我以为它只比较了Widget树。

因此,基本上,我不了解渲染引擎如何决定要更新的内容以及要忽略的内容,因为我看不到如何创建新的List来将任何信息发送到渲染引擎,正如文档所述,渲染引擎只是在寻找新的ListView ...而AFAIK会寻找新的List不会创建新的ListView

1 个答案:

答案 0 :(得分:8)

颤振不仅由Widgets组成。

呼叫setState时,将小部件标记为脏。但是,此小部件实际上并不是您在屏幕上渲染的。 存在用于创建/更改RenderObjects的小部件;这些RenderObjects在屏幕上绘制内容。

RenderObjects和Widget之间的链接使用一种新型的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不会被标记为需要重新布局/重新绘制。因此,不会进行任何视觉更新。