performBoxLayout method

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

Perform layout with typed box constraints

Subclasses override this instead of performLayout. The default implementation sizes to the maxima, treating an unbounded axis as the corresponding lower bound.

Implementation

@override
void performBoxLayout(BoxConstraints constraints) {
  final horizontal = _direction == Axis.horizontal;
  final maxMain = horizontal ? constraints.maxWidth : constraints.maxHeight;
  final childConstraints = horizontal
      ? BoxConstraints(maxWidth: maxMain, maxHeight: constraints.maxHeight)
      : BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: maxMain);
  final runs = <_WrapRun>[];
  var current = _WrapRun();
  for (final child in children.whereType<RenderBox>()) {
    child.layout(childConstraints);
    final childMain = horizontal ? child.size.width : child.size.height;
    final childCross = horizontal ? child.size.height : child.size.width;
    final nextMain = current.items.isEmpty
        ? childMain
        : current.main + _spacing + childMain;
    if (maxMain != null && current.items.isNotEmpty && nextMain > maxMain) {
      runs.add(current);
      current = _WrapRun();
    }
    if (current.items.isNotEmpty) current.main += _spacing;
    current
      ..items.add(_WrapChild(child, childMain, childCross))
      ..main += childMain;
    if (childCross > current.cross) current.cross = childCross;
  }
  if (current.items.isNotEmpty) runs.add(current);

  final naturalMain = runs.fold<int>(
    0,
    (value, run) => run.main > value ? run.main : value,
  );
  final naturalCross = runs.isEmpty
      ? 0
      : runs.fold<int>(0, (value, run) => value + run.cross) +
            _runSpacing * (runs.length - 1);
  final width = horizontal
      ? constraints.constrainWidth(naturalMain)
      : constraints.constrainWidth(naturalCross);
  final height = horizontal
      ? constraints.constrainHeight(naturalCross)
      : constraints.constrainHeight(naturalMain);
  size = Size(width, height);

  final finalMain = horizontal ? width : height;
  final finalCross = horizontal ? height : width;
  final runCrossSizes = runs.map((run) => run.cross).toList(growable: false);
  final runOffsets = _alignedOffsets(
    finalCross,
    runCrossSizes,
    _runSpacing,
    _runAlignment,
  );
  for (var runIndex = 0; runIndex < runs.length; runIndex++) {
    final run = runs[runIndex];
    final mainOffsets = _alignedOffsets(
      finalMain,
      run.items.map((child) => child.main).toList(growable: false),
      _spacing,
      _alignment,
    );
    for (var index = 0; index < run.items.length; index++) {
      final child = run.items[index];
      final crossSlack = run.cross - child.cross;
      final childCross = switch (_crossAxisAlignment) {
        WrapCrossAlignment.start => 0,
        WrapCrossAlignment.end => crossSlack,
        WrapCrossAlignment.center => allocateExactCells(
          crossSlack,
          const <int>[1, 1],
        )[0],
      };
      final main = mainOffsets[index];
      final cross = runOffsets[runIndex] + childCross;
      positionChild(
        child.box,
        horizontal ? main : cross,
        horizontal ? cross : main,
      );
    }
  }
}