> For the complete documentation index, see [llms.txt](https://keenv.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://keenv.gitbook.io/notes/flutter/layout.md).

# layout

## Sublinear layout

flutter 会在每一帧执行一次布局操作，布局计算仅在一次传递中完成。**约束通过父节点调用每个子节点的布局方法的方式向下传递**。子节点递归执行自己的布局操作，通过布局方法返回携带几何信息的渲染对象。一旦渲染对象从布局方法中返回，直到下一帧布局操作都不会被两次访问。这种策略将原本可能独立的测量传递和布局传递合并为单次传递。因此，每个渲染对象在布局过程中最多被访问两次：一次在树的向下传递过程中，一次是树的向上传递过程中。 flutter具有这种通用协议的多种实现。最常用的是`RenderBox`，运行在二维笛卡尔坐标系中。在盒子布局中，**约束是最小和最大宽高**。在布局过程中，子节点通过选择一个满足约束的大小来确定自己的几何信息。子节点布局返回后，由父节点决定子节点在父坐标系中的位置。注意，子节点布局不取决于它的位置，因为它的位置直到它从布局中返回后才确定。因此父节点可以重新定位子节点，而无需重新计算子节点布局。

**更广泛地讲，在布局期间，从父节点流向子节点的唯一信息是约束信息，从子节点流向父节点的唯一信息是几何信息。通过这些不变量可减少布局期间所需的工作量**

* 如果子节点没有被标记为\`**dirty**，只要父节点传递给子节点的约束与上次相同，那么子节点可以在布局时立即返回。
* 如果父节点不使用子节点返回的大小信息，那么如果子节点重新选择了大小父节点也无需重新计算布局。
* 严格约束指只有一个有效的几何信息满足约束。如果父节点提供了严格约束，那么当子节点重新计算布局时父节点无需重新计算自己的布局，尽管父节点在布局时使用了子节点的大小，因为子节点在没有接收到新约束时不能改变自己的大小。
* 渲染对象可以声明它只使用父节点提供的约束来确定自己的几何信息。即使约束不严格且父节点的布局依赖于子节点的大小，当子节点重新计算布局时，父节点也无需重新计算其布局时，因为子节点在没有接收新的约束条件下无法更改其大小。

> 几何：研究空间结构与性质的学科

## Sublinear widget building

...

## RenderBox

### RenderProxyBox

默认情况下，`RenderProxyBox`渲染对象调整自身大小以适合其子节点，如果没有子节点则尽可能小;它传递所有的命中测试(hit testing)和绘制给子节点，固有尺寸和基线测量同样转发给子节点。 `RenderProxyBox`假定子代与父代大小相同并且子节点位于0,0

### RenderShiftedBox

默认情况下，`RenderShiftedBox`的行为与`RenderProxyBox`相似，但是不假定子节点位于0,0，和不提供默认的布局逻辑

### 子节点种类和特定于子节点的数据

`RenderBox`的子节点可以是不限于`RenderBox`的`RenderObject`的子类

子代使用`parentData`字段来存储父代的数据。这个数据必须继承于`ParentData`类。`setupParentData`方法用于初始化`parentData`。

`BoxParentData.offset`字段存储子代相对父代的位置

## Layout

`RenderBox`类实现了布局算法。它们具有一级约束，并基于这些约束和可能具有的其它任何输入（例如：其的子代或属性）来调整自身的大小。

在实现`RenderBox`子类时，必须做出选择。是仅基于约束来确定自身的大小还是使用其它信息。完全基于约束的子类将会变大以适合父代。

完全基于约束调整大小允许系统进行重大优化。使用此方法的类需要重写`sizedByParent`返回`true`，并重写`performResize`仅使用约束来设置`size`

```dart
@override
bool get sizedByParent => true;

@override
void performResize() {
  size = constraints.smallest;
}
```

否则，通过`performLayout`方法设置大小

`performLayout`是渲染框决定size（如果不是`sizedByParent`）,和决定子代位置的地方

### Layout of RenderBox children

`performLayout`方法需要调用每个子代的`layout`方法，并传递描述子代可以在哪里渲染的`BoxConstraints`对象给它。传递严格约束（`BoxConstraints.isTight`）给子代允许渲染库应用一些优化，因为它知道如果约束是严格的，子代的尺寸不会因为子代布局的变化而改变。

如果`performLayout`方法将使子代的大小来影响布局的其它方面，例如如果渲染框围绕子代调整大小，或根据子代的大小来设置这些子代的位置，那么必须设置`layout`方法的`parentUsesSize`参数为`true`

这个标志关闭了一些优化；不依赖于子代大小的算法将更高效。（依赖于子代的`size`意味着如果子代被标志为**dirty**，父代也可能将被标志为**dirty**，除了父代传递给子代的`constraints`是严格约束）

对于不继承自`RenderProxyBox`的`RenderBox`类，一旦它们布局了它们的子代，便也需要通过设置`BoxParentData.offset`字段给每个子代的`parentData`对象来定位它们。

### Layout of no-RenderBox children

...

## Painting

要描述渲染框是如何绘制的，需要实现`paint`方法。
