了解 Flutter 渲染引擎 [英] Understanding Flutter Render Engine

查看:13
本文介绍了了解 Flutter 渲染引擎的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

文档 这里关于如何更新 ListView 说:

The docs here about how to update a ListView say:

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

In Flutter, if you were to update the list of widgets inside a setState(), you would quickly see that your data did not change visually. This is because when setState() is called, the Flutter rendering engine looks at the widget tree to see if anything has changed. When it gets to your ListView, it performs a == check, and determines that the two ListViews are the same. Nothing has changed, so no update is required.

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

For a simple way to update your ListView, create a new List inside of setState(), and copy the data from the old list to the new list.

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

I don't get how the Render Engine determines if there are any changes in the Widget Tree in this case.

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

AFAICS, we care calling setState, which marks the State object as dirty and asks it to rebuild. Once it rebuilds there will be a new ListView, won't it? So how come the == check says it's the same object?

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

Also, the new List will be internal to the State object, does the Flutter engine compare all the objects inside the State object? I thought it only compared the Widget tree.

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

So, basically I don't understand how the Render Engine decides what it's going to update and what's going to ignore, since I can't see how creating a new List sends any information to the Render Engine, as the docs says the Render Engine just looks for a new ListView... And AFAIK a new List won't create a new ListView.

推荐答案

Flutter 不仅仅由 小部件.

Flutter isn't made only of Widgets.

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

When you call setState, you mark the Widget as dirty. But this Widget isn't actually what you render on the screen. Widgets exist to create/mutate RenderObjects; it's these RenderObjects that draw your content on the screen.

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

The link between RenderObjects and Widgets is done using a new kind of Widget: RenderObjectWidget (such as LeafRenderObjectWidget)

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

Most widgets provided by Flutter are to some extent a RenderObjectWidget, including ListView.

一个典型的 RenderObjectWidget 示例如下:

A typical RenderObjectWidget example would be this:

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.但是,通知框架有一些东西需要重新绘制是不够的.

This example uses a widget to create/update a RenderObject. It's not enough to notify the framework that there's something to repaint though.

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

To make a RenderObject repaint, one must call markNeedsPaint or markNeedsLayout on the desired renderObject.

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

This is usually done by the RenderObject itself using custom field setter this way:

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

注意 if (value != previous).

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

This check ensures that when a widget rebuilds without changing anything, Flutter doesn't relayout/repaint anything.

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

It's due to this exact condition that mutating List or Map doesn't make ListView rerender. It basically has the following:

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

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

But it implies that if you mutate the list instead of creating a new one, the RenderObject will not be marked as needing a relayout/repaint. Therefore there won't be any visual update.

这篇关于了解 Flutter 渲染引擎的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆