layout method
Compute the layout for this render object.
This method is called by the framework with constraints from the parent.
It should call performLayout if needed, which must set the size.
The parentUsesSize parameter indicates whether the parent depends on
this render object's size for its own layout. This is used for optimization.
Implementation
void layout(BoxConstraints constraints, {bool parentUsesSize = false}) {
// Always reset error state when layout is called, even if we might skip the actual layout
_hasLayoutError = false;
_lastError = null;
_lastStackTrace = null;
// We can skip layout if:
// 1. This render object doesn't need layout (_needsLayout is false)
// 2. The constraints are IDENTICAL (same object instance, not just equal values)
//
// Note: We intentionally use `identical()` instead of `==` here.
// Using value equality (==) was causing layout bugs in complex component trees
// (e.g., vide_cli's tool renderers) where children would skip relayout when
// their content changed but constraints remained the same by value.
// The identical() check is more conservative and only skips when we're truly
// being called with the exact same constraints object.
if (!_needsLayout && identical(constraints, _constraints)) return;
final constraintsChanged = !identical(constraints, _constraints);
_constraints = constraints;
if (_needsLayout || _size == null || constraintsChanged) {
// Set _needsLayout = false BEFORE calling performLayout so that
// invokeLayoutCallback can be used during layout (its assertion
// checks that we're in the middle of performLayout by verifying
// _needsLayout is false).
_needsLayout = false;
try {
performLayout();
assert(_size != null, 'performLayout() did not set a size');
} catch (e, stack) {
_reportException('performLayout', e, stack);
// Set a default size to prevent cascading failures
_size = constraints.constrain(const Size(10, 5));
_hasLayoutError = true;
}
}
}