layout函数说明
Compute the layout for this render object.
计算render object 的布局
This method is the main entry point for parents to ask their children to update their layout information. The parent passes a constraints object, which informs the child as to which layouts are permissible. The child is required to obey the given constraints.
这个方法是父节点要求子节点更新布局信息的主要入口。父节点传入constraints信息,孩子节点被要求准守给定的约束
If the parent reads information computed during the child's layout, the parent must pass true for parentUsesSize. In that case, the parent will be marked as needing layout whenever the child is marked as needing layout because the parent's layout information depends on the child's layout information. If the parent uses the default value (false) for parentUsesSize, the child can change its layout information (subject to the given constraints) without informing the parent.
在子节点布局期间,如果父节点读取布局信息,父节点必须传parentUsesSize为true。在这种情况下,只要子节点被标记为需要layout,父节点也需要标记为需要layout,由于父节点的布局信息依赖还在的布局信息。如果父节点使用parentUsesSize为false, 孩子能在不需要通知父节点的情况下改变布局信息。
Subclasses should not override layout directly. Instead, they should override performResize and/or performLayout. The layout method delegates the actual work to performResize and performLayout. The parent's performLayout method should call the layout of all its children unconditionally. It is the layout method's responsibility (as implemented here) to return early if the child does not need to do any work to update its layout information.
子类不应该直接重写layout方法。相应的,需要重写performResize and/or performLayout方法。layout方法将实际的工具代理给performResize and/or performLayout。父节点的performLayout方法需要无条件的调用所有孩子的layout。如果孩子节点没有必须要更新布局信息,layout方法需要提前返回,这是他的责任。
layout代码
void layout(Constraints constraints, { bool parentUsesSize = false }) {
// 找布局边界,符合布局边界的条件
// 父节点不使用布局信息
// 父节点觉得size
// constraints 有精确的大小
// 父节点不是RenderObject
RenderObject? relayoutBoundary;
if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject) {
relayoutBoundary = this;
} else {
relayoutBoundary = (parent! as RenderObject)._relayoutBoundary;
}
// 不需要布局,提前返回的情况
// _needsLayout 为false
// constraints == _constraints 约束相同
// 自己就是布局边界
if (!_needsLayout && constraints == _constraints && relayoutBoundary == _relayoutBoundary) {
return;
}
// 存储约束信息
_constraints = constraints;
// 布局边界改变,必须通知孩子节点,他们也需要更新,否则,稍后他们将困惑到底谁是他们的布局边界
if (_relayoutBoundary != null && relayoutBoundary != _relayoutBoundary) {
// The local relayout boundary has changed, must notify children in case
// they also need updating. Otherwise, they will be confused about what
// their actual relayout boundary is later.
visitChildren(_cleanChildRelayoutBoundary);
}
// 保存布局边界
_relayoutBoundary = relayoutBoundary;
assert(!_debugMutationsLocked);
assert(!_doingThisLayoutWithCallback);
// 先求大小
if (sizedByParent) {
try {
performResize();
} catch (e, stack) {
}
}
// 然后布局吧
try {
performLayout();
markNeedsSemanticsUpdate();
} catch (e, stack) {
_debugReportException('performLayout', e, stack);
}
_needsLayout = false;
markNeedsPaint();
}
sizedByParent解释
Whether the constraints are the only input to the sizing algorithm (in particular, child nodes have no impact).
是否表明约束是计算size的唯一输入 也就意味着孩子对他没有影响。
Returning false is always correct, but returning true can be more efficient when computing the size of this render object because we don't need to recompute the size if the constraints don't change.
返回false是一直正确的。在布局过程中 返回true将更有效率。因为,如果约束没有改变,我们不需要重新计算大小。
Typically, subclasses will always return the same value. If the value can change, then, when it does change, the subclass should make sure to call markNeedsLayoutForSizedByParentChange.
一般,子类一直返回同一个值。如果值改变,子类需要调用markNeedsLayoutForSizedByParentChange函数。
Subclasses that return true must not change the dimensions of this render object in performLayout. Instead, that work should be done by performResize or - for subclasses of RenderBox - in RenderBox.computeDryLayout.
ParentData
Base class for data associated with a RenderObject by its parent. 被父节点关联到RenderObject的数据类 Some render objects wish to store data on their children, such as the children's input parameters to the parent's layout algorithm or the children's position relative to other children. 某些render object期望在孩子节点上存储数据,如父节点布局孩子算法的输入参数,孩子相对于其他孩子的位置信息。
Constraints
abstract class Constraints
An abstract set of layout constraints.
Concrete layout models (such as box) will create concrete subclasses to communicate layout constraints between parents and children.
Writing a Constraints subclass
When creating a new RenderObject subclass with a new layout protocol, one will usually need to create a new Constraints subclass to express the input to the layout algorithms.
A Constraints subclass should be immutable (all fields final). There are several members to implement, in addition to whatever fields, constructors, and helper methods one may find useful for a particular layout protocol:
The isTight getter, which should return true if the object represents a case where the RenderObject class has no choice for how to lay itself out. 如果RenderObject没有其他的选择布局自己,那么返回true
For example, BoxConstraints returns true for isTight when both the minimum and maximum widths and the minimum and maximum heights are equal.
The isNormalized getter, which should return true if the object represents its data in its form. Sometimes, it is possible for fields to be redundant with each other, such that several different representations have the same implications. For example, a BoxConstraints instance with its minimum width greater than its maximum width is equivalent to one where the maximum width is set to that minimum width (2 1 is equivalent to 2 2, since minimum constraints have priority). This getter is used by the default implementation of debugAssertIsValid.
The debugAssertIsValid method, which should assert if there's anything wrong with the constraints object. (We use this approach rather than asserting in constructors so that our constructors can be const and so that it is possible to create invalid constraints temporarily while building valid ones.) See the implementation of BoxConstraints.debugAssertIsValid for an example of the detailed checks that can be made.
The == operator and the hashCode getter, so that constraints can be compared for equality. If a render object is given constraints that are equal, then the rendering library will avoid laying the object out again if it is not dirty. The toString method, which should describe the constraints so that they appear in a usefully readable form in the output of debugDumpRenderTree.
BoxConstraints
class BoxConstraints extends Constraints
Immutable layout constraints for RenderBox layout.
A Size respects a BoxConstraints if, and only if, all of the following relations hold:
minWidth = Size.width = maxWidth
minHeight = Size.height = maxHeight
The constraints themselves must satisfy these relations:
0.0 = minWidth = maxWidth = double.infinity
0.0 = minHeight = maxHeight = double.infinity
double.infinity is a legal value for each constraint.
The box layout model
Render objects in the Flutter framework are laid out by a one-pass layout model which walks down the render tree passing constraints, then walks back up the render tree passing concrete geometry.
For boxes, the constraints are BoxConstraints, which, as described herein, consist of four numbers: a minimum width minWidth, a maximum width maxWidth, a minimum height minHeight, and a maximum height maxHeight.
The geometry for boxes consists of a Size, which must satisfy the constraints described above.
Each RenderBox (the objects that provide the layout models for box widgets) receives BoxConstraints from its parent, then lays out each of its children, then picks a Size that satisfies the BoxConstraints.
Render objects position their children independently of laying them out. Frequently, the parent will use the children's sizes to determine their position. A child does not know its position and will not necessarily be laid out again, or repainted, if its position changes.
Terminology
When the minimum constraints and the maximum constraint in an axis are the same, that axis is tightly constrained. See: new BoxConstraints.tightFor, new BoxConstraints.tightForFinite, tighten, hasTightWidth, hasTightHeight, isTight. 当最小和最大约束在某个轴上相同,这个轴是紧凑约束。
An axis with a minimum constraint of 0.0 is loose (regardless of the maximum constraint; if it is also 0.0, then the axis is simultaneously tight and loose!). See: new BoxConstraints.loose, loosen. 如果某个轴的最小约束是0, 那么该轴是loose,不管maximun是什么。
An axis whose maximum constraint is not infinite is bounded. See: hasBoundedWidth, hasBoundedHeight. 当一个轴的maximum不是无限的,叫做有边界约束。
An axis whose maximum constraint is infinite is unbounded. An axis is expanding if it is tightly infinite (its minimum and maximum constraints are both infinite). See: new BoxConstraints.expand. 当一个轴的maximum是无限的,该轴是无边际的。如果最小轴也是无限的,那么就expanding
An axis whose minimum constraint is infinite is just said to be infinite (since by definition the maximum constraint must also be infinite in that case). See: hasInfiniteWidth, hasInfiniteHeight. 如果最小轴是无限的,那么叫做无限的
A size is constrained when it satisfies a BoxConstraints description. See: constrain, constrainWidth, constrainHeight, constrainDimensions, constrainSizeAndAttemptToPreserveAspectRatio, isSatisfiedBy.