Layout protocol
One pass, not a negotiation
A parent passes BoxConstraints — minimum and maximum width and height — to each child. The child picks a Size within those bounds and returns it. The parent then positions each child and reports its own size upward. No child ever asks its parent how much room it has; it is told, and it answers.
Because there is exactly one downward and one upward step per render object, layout stays linear in the size of the tree. That property is what keeps rebuilding large subtrees on every state change practical.
Writing PerformLayout
A render object implements the protocol in PerformLayout: deflate the incoming constraints for whatever space you consume, lay the child out, position it, then return your own size constrained to what the parent allowed.
// A parent hands down constraints; the child answers with a size.
protected override Size PerformLayout(BoxConstraints constraints)
{
var childConstraints = constraints.Deflate(Padding);
var childSize = Child.Layout(childConstraints, parentUsesSize: true);
Child.ParentData.Offset = new Offset(Padding.Left, Padding.Top);
return constraints.Constrain(
new Size(
childSize.Width + Padding.Horizontal,
childSize.Height + Padding.Vertical
)
);
}Pass parentUsesSize: true only when your own size actually depends on the child's. It is the signal the framework uses to decide how far a relayout has to propagate.
Bounded and unbounded axes
An axis is unbounded when its maximum is infinite — inside a scroll view along the scroll direction, for example. A child that wants to fill available space has nothing to fill, which is the source of the familiar "unbounded constraints" error. The usual fixes are the same as in Flutter: give the child an intrinsic size, wrap it in a box that imposes one, or use Expanded only where the main axis is genuinely bounded.
After layout: paint and hit-test
Once sizes and offsets are settled, the render tree paints into layers, and hit-testing walks the same geometry in reverse to find which render object is under the pointer. Both phases belong to Plumix — Avalonia only supplies the surface that the finished frame is drawn onto, as described on the architecture page.
The core widgets list shows which boxes manipulate constraints directly — SizedBox, OverflowBox, LimitedBox, UnconstrainedBox and FractionallySizedBox.
