了解颤振渲染引擎

mFe*_*ein 9 flutter flutter-layout

这里的文档关于如何更新ListView发言权:

在Flutter中,如果要更新setState()中的小部件列表,您会很快发现您的数据没有直观地改变.这是因为当调用setState()时,Flutter呈现引擎会查看窗口小部件树以查看是否有任何更改.当它到达ListView时,它执行==检查,并确定两个ListView是相同的.没有任何改变,因此不需要更新.

有关更新ListView的简单方法,请在setState()内创建一个新List,并将旧列表中的数据复制到新列表中.

我不知道渲染引擎如何确定在这种情况下Widget Tree中是否有任何更改.

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

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

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

Rém*_*let 13

颤动不仅仅是小部件.

当您调用时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;
    }
}
Run Code Online (Sandbox Code Playgroud)

此示例使用窗口小部件来创建/更新RenderObject.仅仅通知框架有一些东西可以重新绘制是不够的.

要进行RenderObject重绘,必须调用markNeedsPaintmarkNeedsLayout在所需的renderObject上调用.

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

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

请注意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;
  }
}
Run Code Online (Sandbox Code Playgroud)

但它暗示如果您改变列表而不是创建新列表,则RenderObject将不会被标记为需要重新布局/重绘.因此,不会有任何视觉更新.