layout method

void layout (Constraints constraints, { bool parentUsesSize: false })

Compute the layout for this render object.

This method is the main entry point for parents to ask their children to update their layout information. The parent passes a constraints object, which informs the child as which layouts are permissible. The child is required to obey the given constraints.

If the parent reads information computed during the child's layout, the parent must pass true for parentUsesSize. In that case, the parent will be marked as needing layout whenever the child is marked as needing layout because the parent's layout information depends on the child's layout information. If the parent uses the default value (false) for parentUsesSize, the child can change its layout information (subject to the given constraints) without informing the parent.

Subclasses should not override layout directly. Instead, they should override performResize and/or performLayout. The layout method delegates the actual work to performResize and performLayout.

The parent's performLayout method should call the layout of all its children unconditionally. It is the layout method's responsibility (as implemented here) to return early if the child does not need to do any work to update its layout information.

Implementation

void layout(Constraints constraints, { bool parentUsesSize = false }) {
  assert(constraints != null);
  assert(constraints.debugAssertIsValid(
    isAppliedConstraint: true,
    informationCollector: (StringBuffer information) {
      final List<String> stack = StackTrace.current.toString().split('\n');
      int targetFrame;
      final Pattern layoutFramePattern = RegExp(r'^#[0-9]+ +RenderObject.layout \(');
      for (int i = 0; i < stack.length; i += 1) {
        if (layoutFramePattern.matchAsPrefix(stack[i]) != null) {
          targetFrame = i + 1;
          break;
        }
      }
      if (targetFrame != null && targetFrame < stack.length) {
        information.writeln(
          'These invalid constraints were provided to $runtimeType\'s layout() '
          'function by the following function, which probably computed the '
          'invalid constraints in question:'
        );
        final Pattern targetFramePattern = RegExp(r'^#[0-9]+ +(.+)$');
        final Match targetFrameMatch = targetFramePattern.matchAsPrefix(stack[targetFrame]);
        if (targetFrameMatch != null && targetFrameMatch.groupCount > 0) {
          information.writeln('  ${targetFrameMatch.group(1)}');
        } else {
          information.writeln(stack[targetFrame]);
        }
      }
    },
  ));
  assert(!_debugDoingThisResize);
  assert(!_debugDoingThisLayout);
  RenderObject relayoutBoundary;
  if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject) {
    relayoutBoundary = this;
  } else {
    final RenderObject parent = this.parent;
    relayoutBoundary = parent._relayoutBoundary;
  }
  assert(() {
    _debugCanParentUseSize = parentUsesSize;
    return true;
  }());
  if (!_needsLayout && constraints == _constraints && relayoutBoundary == _relayoutBoundary) {
    assert(() {
      // in case parentUsesSize changed since the last invocation, set size
      // to itself, so it has the right internal debug values.
      _debugDoingThisResize = sizedByParent;
      _debugDoingThisLayout = !sizedByParent;
      final RenderObject debugPreviousActiveLayout = _debugActiveLayout;
      _debugActiveLayout = this;
      debugResetSize();
      _debugActiveLayout = debugPreviousActiveLayout;
      _debugDoingThisLayout = false;
      _debugDoingThisResize = false;
      return true;
    }());
    return;
  }
  _constraints = constraints;
  _relayoutBoundary = relayoutBoundary;
  assert(!_debugMutationsLocked);
  assert(!_doingThisLayoutWithCallback);
  assert(() {
    _debugMutationsLocked = true;
    if (debugPrintLayouts)
      debugPrint('Laying out (${sizedByParent ? "with separate resize" : "with resize allowed"}) $this');
    return true;
  }());
  if (sizedByParent) {
    assert(() { _debugDoingThisResize = true; return true; }());
    try {
      performResize();
      assert(() { debugAssertDoesMeetConstraints(); return true; }());
    } catch (e, stack) {
      _debugReportException('performResize', e, stack);
    }
    assert(() { _debugDoingThisResize = false; return true; }());
  }
  RenderObject debugPreviousActiveLayout;
  assert(() {
    _debugDoingThisLayout = true;
    debugPreviousActiveLayout = _debugActiveLayout;
    _debugActiveLayout = this;
    return true;
  }());
  try {
    performLayout();
    markNeedsSemanticsUpdate();
    assert(() { debugAssertDoesMeetConstraints(); return true; }());
  } catch (e, stack) {
    _debugReportException('performLayout', e, stack);
  }
  assert(() {
    _debugActiveLayout = debugPreviousActiveLayout;
    _debugDoingThisLayout = false;
    _debugMutationsLocked = false;
    return true;
  }());
  _needsLayout = false;
  markNeedsPaint();
}