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 to 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: () sync* {
      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) {
        final Pattern targetFramePattern = RegExp(r'^#[0-9]+ +(.+)$');
        final Match targetFrameMatch = targetFramePattern.matchAsPrefix(stack[targetFrame]);
        final String problemFunction = (targetFrameMatch != null && targetFrameMatch.groupCount > 0) ? targetFrameMatch.group(1) : stack[targetFrame].trim();
        // TODO(jacobr): this case is similar to displaying a single stack frame.
        yield ErrorDescription(
          'These invalid constraints were provided to $runtimeType\'s layout() '
          'function by the following function, which probably computed the '
          'invalid constraints in question:\n'
          '  $problemFunction'
        );
      }
    },
  ));
  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();
}