showOnScreen method

  1. @override
void showOnScreen({
  1. RenderObject? descendant,
  2. Rect? rect,
  3. Duration duration = Duration.zero,
  4. Curve curve = Curves.ease,
})
override

Attempt to make (a portion of) this or a descendant RenderObject visible on screen.

If descendant is provided, that RenderObject is made visible. If descendant is omitted, this RenderObject is made visible.

The optional rect parameter describes which area of that RenderObject should be shown on screen. If rect is null, the entire RenderObject (as defined by its paintBounds) will be revealed. The rect parameter is interpreted relative to the coordinate system of descendant if that argument is provided and relative to this RenderObject otherwise.

The duration parameter can be set to a non-zero value to bring the target object on screen in an animation defined by curve.

See also:

Implementation

@override
void showOnScreen({
  RenderObject? descendant,
  Rect? rect,
  Duration duration = Duration.zero,
  Curve curve = Curves.ease,
}) {
  final CSSOverflowType overflowX = renderStyle.effectiveOverflowX;
  final CSSOverflowType overflowY = renderStyle.effectiveOverflowY;

  final bool xScrollable = (overflowX == CSSOverflowType.scroll ||
          overflowX == CSSOverflowType.auto) &&
      scrollOffsetX != null;
  final bool yScrollable = (overflowY == CSSOverflowType.scroll ||
          overflowY == CSSOverflowType.auto) &&
      scrollOffsetY != null;

  if ((!xScrollable && !yScrollable) ||
      !hasSize ||
      descendant == null ||
      descendant is! RenderBox) {
    return super.showOnScreen(
        descendant: descendant, rect: rect, duration: duration, curve: curve);
  }

  final Size? viewport = _viewportSize;
  final Size? content = _scrollableSize;
  if (viewport == null || content == null) {
    return super.showOnScreen(
        descendant: descendant, rect: rect, duration: duration, curve: curve);
  }

  final double oldScrollTop = scrollTop;
  final double oldScrollLeft = scrollLeft;
  final double oldPaintOffsetX = _paintOffsetX;
  final double oldPaintOffsetY = _paintOffsetY;

  final Rect targetRect = rect ?? descendant.paintBounds;
  final Matrix4 transform = descendant.getTransformTo(this as RenderObject);
  final Rect bounds = MatrixUtils.transformRect(transform, targetRect);

  double targetScrollTop = oldScrollTop;
  double targetScrollLeft = oldScrollLeft;

  if (yScrollable && scrollOffsetY != null) {
    final double maxY = math.max(0.0, content.height - viewport.height);
    if (bounds.top < 0.0) {
      targetScrollTop += bounds.top;
    } else if (bounds.bottom > size.height) {
      targetScrollTop += (bounds.bottom - size.height);
    }
    targetScrollTop = targetScrollTop.clamp(0.0, maxY).toDouble();
    if (duration == Duration.zero) {
      scrollOffsetY!.jumpTo(targetScrollTop);
    } else {
      scrollOffsetY!
          .animateTo(targetScrollTop, duration: duration, curve: curve);
    }
  }

  if (xScrollable && scrollOffsetX != null) {
    final double maxX = math.max(0.0, content.width - viewport.width);
    targetScrollLeft = scrollLeft;

    final AxisDirection axisDirectionX =
        (renderStyle.direction == TextDirection.rtl)
            ? AxisDirection.left
            : AxisDirection.right;

    switch (axisDirectionX) {
      case AxisDirection.right:
        if (bounds.left < 0.0) {
          targetScrollLeft += bounds.left;
        } else if (bounds.right > size.width) {
          targetScrollLeft += (bounds.right - size.width);
        }
        break;
      case AxisDirection.left:
        if (bounds.right > size.width) {
          targetScrollLeft -= (bounds.right - size.width);
        } else if (bounds.left < 0.0) {
          targetScrollLeft -= bounds.left;
        }
        break;
      case AxisDirection.up:
      case AxisDirection.down:
        break;
    }

    targetScrollLeft = targetScrollLeft.clamp(0.0, maxX).toDouble();
    if (duration == Duration.zero) {
      scrollOffsetX!.jumpTo(targetScrollLeft);
    } else {
      scrollOffsetX!
          .animateTo(targetScrollLeft, duration: duration, curve: curve);
    }
  }

  // Let ancestors handle any additional scrolling (e.g. nested scroll views).
  // IMPORTANT: forward the *revealed* descendant bounds (in this coordinate space),
  // not `rect: null`. Passing null causes ancestors to attempt to reveal this
  // entire scroll container's paint bounds, which can incorrectly scroll the
  // outer page (e.g. jump-to-top when focusing an input).
  final double newPaintOffsetY = -targetScrollTop;
  final double deltaPaintY = newPaintOffsetY - oldPaintOffsetY;

  double deltaPaintX = 0.0;
  if (xScrollable) {
    final double maxX = math.max(0.0, content.width - viewport.width);
    final bool isRTL = renderStyle.direction == TextDirection.rtl;
    final double newLogicalLeft = isRTL ? (maxX - targetScrollLeft) : targetScrollLeft;
    final double newPaintOffsetX = -newLogicalLeft;
    deltaPaintX = newPaintOffsetX - oldPaintOffsetX;
  }

  final Rect revealed = bounds.shift(Offset(deltaPaintX, deltaPaintY));
  super.showOnScreen(
    descendant: this as RenderObject,
    rect: revealed,
    duration: duration,
    curve: curve,
  );
}