layout method
Implementation
@override
void layout(BoxConstraints constraints) {
super.layout(constraints);
var maxWidth = 0.0;
var maxHeight = 0.0;
// For StackFit.expand we know the final size up-front from constraints,
// so we can skip the first measurement pass entirely and lay out each
// child exactly once with tight constraints.
final isExpand = fit == StackFit.expand;
final expandWidth = isExpand && constraints.hasBoundedWidth
? constraints.maxWidth
: null;
final expandHeight = isExpand && constraints.hasBoundedHeight
? constraints.maxHeight
: null;
if (isExpand && expandWidth != null && expandHeight != null) {
// Single-pass: lay out each child once with the correct constraints.
for (final child in children) {
final data = child.parentData as StackParentData?;
BoxConstraints childConstraints;
if (data != null && data.isPositioned) {
final left = _resolveDimensionDouble(data.left);
final right = _resolveDimensionDouble(data.right);
final top = _resolveDimensionDouble(data.top);
final bottom = _resolveDimensionDouble(data.bottom);
final childWidth =
_resolveDimensionDouble(data.width) ??
(left != null && right != null
? math.max(0, expandWidth - left - right)
: null);
final childHeight =
_resolveDimensionDouble(data.height) ??
(top != null && bottom != null
? math.max(0, expandHeight - top - bottom)
: null);
if (childWidth != null && childHeight != null) {
childConstraints = BoxConstraints.tight(
Size(childWidth, childHeight),
);
} else {
// Positioned child without fully determined dimensions: use loose
// with stack size as max, then it will report its natural size.
childConstraints = BoxConstraints(
maxWidth: expandWidth,
maxHeight: expandHeight,
);
}
} else {
childConstraints = BoxConstraints.tight(
Size(expandWidth, expandHeight),
);
}
child.layout(childConstraints);
maxWidth = math.max(maxWidth, child.size.width);
maxHeight = math.max(maxHeight, child.size.height);
}
size = constraints.constrain(Size(expandWidth, expandHeight));
return;
}
// Two-pass layout for non-expand modes:
// Pass 1: measure children with loose constraints.
final looseConstraints = BoxConstraints(
maxWidth: constraints.maxWidth,
maxHeight: constraints.maxHeight,
);
for (final child in children) {
child.layout(looseConstraints);
maxWidth = math.max(maxWidth, child.size.width);
maxHeight = math.max(maxHeight, child.size.height);
}
var resolvedWidth = _resolveDimensionDouble(width) ?? maxWidth;
var resolvedHeight = _resolveDimensionDouble(height) ?? maxHeight;
if (resolvedWidth.isInfinite) {
resolvedWidth = maxWidth;
}
if (resolvedHeight.isInfinite) {
resolvedHeight = maxHeight;
}
// Pass 2: re-layout only positioned children whose constraints changed.
for (var i = 0; i < children.length; i++) {
final child = children[i];
final data = child.parentData as StackParentData?;
if (data != null && data.isPositioned) {
final left = _resolveDimensionDouble(data.left);
final right = _resolveDimensionDouble(data.right);
final top = _resolveDimensionDouble(data.top);
final bottom = _resolveDimensionDouble(data.bottom);
final childWidth =
_resolveDimensionDouble(data.width) ??
(left != null && right != null
? math.max(0, resolvedWidth - left - right)
: child.size.width);
final childHeight =
_resolveDimensionDouble(data.height) ??
(top != null && bottom != null
? math.max(0, resolvedHeight - top - bottom)
: child.size.height);
final childConstraints = BoxConstraints.tight(
Size(childWidth, childHeight),
);
child.layout(childConstraints);
}
// Non-positioned children with StackFit.loose already have correct
// sizes from pass 1 — skip re-layout.
}
size = constraints.constrain(Size(resolvedWidth, resolvedHeight));
}