layout method

  1. @override
void layout(
  1. BoxConstraints constraints
)
override

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));
}