performLayout method

  1. @override
void performLayout()
override

Do the work of computing the layout for this render object.

Do not call this function directly: call layout instead. This function is called by layout when there is actually work to be done by this render object during layout. The layout constraints provided by your parent are available via the constraints getter.

If sizedByParent is true, then this function should not actually change the dimensions of this render object. Instead, that work should be done by performResize. If sizedByParent is false, then this function should both change the dimensions of this render object and instruct its children to layout.

In implementing this function, you must call layout on each of your children, passing true for parentUsesSize if your layout information is dependent on your child's layout information. Passing true for parentUsesSize ensures that this render object will undergo layout if the child undergoes layout. Otherwise, the child can change its layout information without informing this render object.

Implementation

@override
void performLayout() {
  if (center == null) {
    assert(firstChild == null, 'center must be null if children are present');
    _minScrollExtent = 0.0;
    _maxScrollExtent = 0.0;
    _hasVisualOverflow = false;
    offset.applyContentDimensions(0, 0);
    return;
  }

  assert(center!.parent == this, 'center must be a child of the viewport');

  final constraints = this.constraints;
  if (firstChild == null) {
    switch (axis) {
      case Axis.vertical:
        assert(
          constraints.hasBoundedWidth,
          'Vertical viewport was given '
          'unbounded width.\n'
          'Viewports expand in the cross axis to fill their container and '
          'constrain their children to match their extent in the cross axis. '
          'In this case, a vertical viewport was given an unlimited amount '
          'of horizontal space in which to expand.',
        );
        size = Size(constraints.maxWidth, constraints.minHeight);
        break;
      case Axis.horizontal:
        assert(
          constraints.hasBoundedHeight,
          'Horizontal viewport was given '
          'unbounded height.\n'
          'Viewports expand in the cross axis to fill their container and '
          'constrain their children to match their extent in the cross axis. '
          'In this case, a horizontal viewport was given an unlimited amount '
          'of vertical space in which to expand.',
        );
        size = Size(constraints.minWidth, constraints.maxHeight);
        break;
    }
    offset.applyViewportDimension(0);
    _maxScrollExtent = 0.0;
    _shrinkWrapExtent = 0.0;
    _hasVisualOverflow = false;
    offset.applyContentDimensions(0, 0);
    return;
  }

  double mainAxisExtent;
  final double crossAxisExtent;
  switch (axis) {
    case Axis.vertical:
      assert(
        constraints.hasBoundedWidth,
        'Vertical viewport was given '
        'unbounded width.\n'
        'Viewports expand in the cross axis to fill their container and '
        'constrain their children to match their extent in the cross axis. '
        'In this case, a vertical viewport was given an unlimited amount '
        'of horizontal space in which to expand.',
      );
      mainAxisExtent = constraints.maxHeight;
      crossAxisExtent = constraints.maxWidth;
      break;
    case Axis.horizontal:
      assert(
        constraints.hasBoundedHeight,
        'Horizontal viewport was given '
        'unbounded height.\n'
        'Viewports expand in the cross axis to fill their container and '
        'constrain their children to match their extent in the cross axis. '
        'In this case, a horizontal viewport was given an unlimited amount '
        'of vertical space in which to expand.',
      );
      mainAxisExtent = constraints.maxWidth;
      crossAxisExtent = constraints.maxHeight;
      break;
  }

  if (mainAxisExtent.isInfinite) {
    mainAxisExtent = _maxMainAxisExtent;
  }

  final centerOffsetAdjustment = center!.centerOffsetAdjustment;

  double correction;
  double effectiveExtent;
  do {
    correction = _attemptLayout(
      mainAxisExtent,
      crossAxisExtent,
      offset.pixels + centerOffsetAdjustment,
    );
    if (correction != 0.0) {
      offset.correctBy(correction);
    } else {
      switch (axis) {
        case Axis.vertical:
          effectiveExtent = constraints.constrainHeight(_shrinkWrapExtent);
          break;
        case Axis.horizontal:
          effectiveExtent = constraints.constrainWidth(_shrinkWrapExtent);
          break;
      }
      // *** Difference from [RenderViewport].
      final top = _minScrollExtent + mainAxisExtent * anchor;
      final bottom = _maxScrollExtent - mainAxisExtent * (1.0 - anchor);

      final maxScrollOffset = math.max<double>(math.min(0, top), bottom);
      final minScrollOffset = math.min<double>(top, maxScrollOffset);

      final didAcceptViewportDimension =
          offset.applyViewportDimension(effectiveExtent);
      final didAcceptContentDimension =
          offset.applyContentDimensions(minScrollOffset, maxScrollOffset);
      if (didAcceptViewportDimension && didAcceptContentDimension) {
        break;
      }
    }
  } while (true);
  switch (axis) {
    case Axis.vertical:
      size =
          constraints.constrainDimensions(crossAxisExtent, effectiveExtent);
      break;
    case Axis.horizontal:
      size =
          constraints.constrainDimensions(effectiveExtent, crossAxisExtent);
      break;
  }
}