layout method

  1. @override
void layout(
  1. Context context,
  2. BoxConstraints constraints, {
  3. bool parentUsesSize = false,
})
override

First widget pass to calculate the children layout and bounding box

Implementation

@override
void layout(Context context, BoxConstraints constraints,
    {bool parentUsesSize = false}) {
  if (children.isEmpty || _context.firstChild >= children.length) {
    box = PdfRect.fromPoints(PdfPoint.zero, constraints.smallest);
    return;
  }

  BoxConstraints? childConstraints;
  double? mainAxisLimit = 0.0;
  var flipMainAxis = false;
  var flipCrossAxis = false;

  switch (direction) {
    case Axis.horizontal:
      childConstraints = BoxConstraints(maxWidth: constraints.maxWidth);
      mainAxisLimit = constraints.maxWidth;
      if (verticalDirection == VerticalDirection.down) {
        flipCrossAxis = true;
      }
      break;
    case Axis.vertical:
      childConstraints = BoxConstraints(maxHeight: constraints.maxHeight);
      mainAxisLimit = constraints.maxHeight;
      if (verticalDirection == VerticalDirection.down) {
        flipMainAxis = true;
      }
      break;
  }

  final runMetrics = <_RunMetrics>[];
  final childRunMetrics = <Widget, int>{};
  var mainAxisExtent = 0.0;
  var crossAxisExtent = 0.0;
  var runMainAxisExtent = 0.0;
  var runCrossAxisExtent = 0.0;
  var childCount = 0;

  for (final child in children.sublist(_context.firstChild)) {
    child.layout(context, childConstraints, parentUsesSize: true);

    final childMainAxisExtent = _getMainAxisExtent(child)!;
    final childCrossAxisExtent = _getCrossAxisExtent(child)!;

    if (childCount > 0 &&
        runMainAxisExtent + spacing + childMainAxisExtent > mainAxisLimit) {
      mainAxisExtent = math.max(mainAxisExtent, runMainAxisExtent);
      crossAxisExtent += runCrossAxisExtent;
      if (runMetrics.isNotEmpty) {
        crossAxisExtent += runSpacing;
      }
      runMetrics.add(
          _RunMetrics(runMainAxisExtent, runCrossAxisExtent, childCount));
      runMainAxisExtent = 0.0;
      runCrossAxisExtent = 0.0;
      childCount = 0;
    }

    runMainAxisExtent += childMainAxisExtent;

    if (childCount > 0) {
      runMainAxisExtent += spacing;
    }

    runCrossAxisExtent = math.max(runCrossAxisExtent, childCrossAxisExtent);
    childCount += 1;

    childRunMetrics[child] = runMetrics.length;
  }

  if (childCount > 0) {
    mainAxisExtent = math.max(mainAxisExtent, runMainAxisExtent);
    crossAxisExtent += runCrossAxisExtent;
    if (runMetrics.isNotEmpty) {
      crossAxisExtent += runSpacing;
    }
    runMetrics
        .add(_RunMetrics(runMainAxisExtent, runCrossAxisExtent, childCount));
  }

  final runCount = runMetrics.length;
  assert(runCount > 0);

  double? containerMainAxisExtent = 0.0;
  double? containerCrossAxisExtent = 0.0;

  switch (direction) {
    case Axis.horizontal:
      box = PdfRect.fromPoints(PdfPoint.zero,
          constraints.constrain(PdfPoint(mainAxisExtent, crossAxisExtent)));
      containerMainAxisExtent = box!.width;
      containerCrossAxisExtent = box!.height;
      break;
    case Axis.vertical:
      box = PdfRect.fromPoints(PdfPoint.zero,
          constraints.constrain(PdfPoint(crossAxisExtent, mainAxisExtent)));
      containerMainAxisExtent = box!.height;
      containerCrossAxisExtent = box!.width;
      break;
  }

  final crossAxisFreeSpace =
      math.max(0.0, containerCrossAxisExtent - crossAxisExtent);
  var runLeadingSpace = 0.0;
  var runBetweenSpace = 0.0;

  switch (runAlignment) {
    case WrapAlignment.start:
      break;
    case WrapAlignment.end:
      runLeadingSpace = crossAxisFreeSpace;
      break;
    case WrapAlignment.center:
      runLeadingSpace = crossAxisFreeSpace / 2.0;
      break;
    case WrapAlignment.spaceBetween:
      runBetweenSpace =
          runCount > 1 ? crossAxisFreeSpace / (runCount - 1) : 0.0;
      break;
    case WrapAlignment.spaceAround:
      runBetweenSpace = crossAxisFreeSpace / runCount;
      runLeadingSpace = runBetweenSpace / 2.0;
      break;
    case WrapAlignment.spaceEvenly:
      runBetweenSpace = crossAxisFreeSpace / (runCount + 1);
      runLeadingSpace = runBetweenSpace;
      break;
  }

  runBetweenSpace += runSpacing;
  var crossAxisOffset = flipCrossAxis
      ? containerCrossAxisExtent - runLeadingSpace
      : runLeadingSpace;

  _context.lastChild = _context.firstChild;
  for (var i = 0; i < runCount; ++i) {
    final metrics = runMetrics[i];
    final runMainAxisExtent = metrics.mainAxisExtent;
    final runCrossAxisExtent = metrics.crossAxisExtent;
    final childCount = metrics.childCount;

    final mainAxisFreeSpace =
        math.max(0.0, containerMainAxisExtent - runMainAxisExtent);
    var childLeadingSpace = 0.0;
    var childBetweenSpace = 0.0;

    switch (alignment) {
      case WrapAlignment.start:
        break;
      case WrapAlignment.end:
        childLeadingSpace = mainAxisFreeSpace;
        break;
      case WrapAlignment.center:
        childLeadingSpace = mainAxisFreeSpace / 2.0;
        break;
      case WrapAlignment.spaceBetween:
        childBetweenSpace =
            childCount > 1 ? mainAxisFreeSpace / (childCount - 1) : 0.0;
        break;
      case WrapAlignment.spaceAround:
        childBetweenSpace = mainAxisFreeSpace / childCount;
        childLeadingSpace = childBetweenSpace / 2.0;
        break;
      case WrapAlignment.spaceEvenly:
        childBetweenSpace = mainAxisFreeSpace / (childCount + 1);
        childLeadingSpace = childBetweenSpace;
        break;
    }

    childBetweenSpace += spacing;
    var childMainPosition = flipMainAxis
        ? containerMainAxisExtent - childLeadingSpace
        : childLeadingSpace;

    if (flipCrossAxis) {
      crossAxisOffset -= runCrossAxisExtent;
    }

    if (crossAxisOffset < -.01 ||
        crossAxisOffset + runCrossAxisExtent >
            containerCrossAxisExtent + .01) {
      break;
    }

    var currentWidget = _context.lastChild;
    for (final child in children.sublist(currentWidget)) {
      final runIndex = childRunMetrics[child];
      if (runIndex != i) {
        break;
      }

      currentWidget++;
      final childMainAxisExtent = _getMainAxisExtent(child);
      final childCrossAxisExtent = _getCrossAxisExtent(child)!;
      final childCrossAxisOffset = _getChildCrossAxisOffset(
          flipCrossAxis, runCrossAxisExtent, childCrossAxisExtent);
      if (flipMainAxis) {
        childMainPosition -= childMainAxisExtent!;
      }
      child.box = PdfRect.fromPoints(
          _getOffset(
              childMainPosition, crossAxisOffset + childCrossAxisOffset),
          child.box!.size);
      if (flipMainAxis) {
        childMainPosition -= childBetweenSpace;
      } else {
        childMainPosition += childMainAxisExtent! + childBetweenSpace;
      }
    }

    if (flipCrossAxis) {
      crossAxisOffset -= runBetweenSpace;
    } else {
      crossAxisOffset += runCrossAxisExtent + runBetweenSpace;
    }

    _context.lastChild = currentWidget;
  }
}