showOnScreen method Null safety

  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 PersistentHeaderShowOnScreenConfiguration? showOnScreen = showOnScreenConfiguration;
  if (showOnScreen == null)
    return super.showOnScreen(descendant: descendant, rect: rect, duration: duration, curve: curve);

  assert(child != null || descendant == null);
  // We prefer the child's coordinate space (instead of the sliver's) because
  // it's easier for us to convert the target rect into target extents: when
  // the sliver is sitting above the leading edge (not possible with pinned
  // headers), the leading edge of the sliver and the leading edge of the child
  // will not be aligned. The only exception is when child is null (and thus
  // descendant == null).
  final Rect? childBounds = descendant != null
    ? MatrixUtils.transformRect(descendant.getTransformTo(child), rect ?? descendant.paintBounds)
    : rect;

  double targetExtent;
  Rect? targetRect;
  switch (applyGrowthDirectionToAxisDirection(constraints.axisDirection, constraints.growthDirection)) {
    case AxisDirection.up:
      targetExtent = childExtent - (childBounds?.top ?? 0);
      targetRect = _trim(childBounds, bottom: childExtent);
      break;
    case AxisDirection.right:
      targetExtent = childBounds?.right ?? childExtent;
      targetRect = _trim(childBounds, left: 0);
      break;
    case AxisDirection.down:
      targetExtent = childBounds?.bottom ?? childExtent;
      targetRect = _trim(childBounds, top: 0);
      break;
    case AxisDirection.left:
      targetExtent = childExtent - (childBounds?.left ?? 0);
      targetRect = _trim(childBounds, right: childExtent);
      break;
  }

  // A stretch header can have a bigger childExtent than maxExtent.
  final double effectiveMaxExtent = math.max(childExtent, maxExtent);

  targetExtent = targetExtent.clamp(
      showOnScreen.minShowOnScreenExtent,
      showOnScreen.maxShowOnScreenExtent,
    )
    // Clamp the value back to the valid range after applying additional
    // constraints. Contracting is not allowed.
    .clamp(childExtent, effectiveMaxExtent);

  // Expands the header if needed, with animation.
  if (targetExtent > childExtent) {
    final double targetScrollOffset = maxExtent - targetExtent;
    assert(
      vsync != null,
      'vsync must not be null if the floating header changes size animatedly.',
    );
    _updateAnimation(duration, targetScrollOffset, curve);
    _controller?.forward(from: 0.0);
  }

  super.showOnScreen(
    descendant: descendant == null ? this : child,
    rect: targetRect,
    duration: duration,
    curve: curve,
  );
}