getOffsetToReveal method
- RenderObject target,
- double alignment, {
- Rect? rect,
- Axis? axis,
Returns the offset that would be needed to reveal the target
RenderObject.
This is used by RenderViewportBase.showInViewport, which is itself used by RenderObject.showOnScreen for RenderViewportBase, which is in turn used by the semantics system to implement scrolling for accessibility tools.
The optional rect
parameter describes which area of that target
object
should be revealed in the viewport. If rect
is null, the entire
target
RenderObject (as defined by its RenderObject.paintBounds)
will be revealed. If rect
is provided it has to be given in the
coordinate system of the target
object.
The alignment
argument describes where the target should be positioned
after applying the returned offset. If alignment
is 0.0, the child must
be positioned as close to the leading edge of the viewport as possible. If
alignment
is 1.0, the child must be positioned as close to the trailing
edge of the viewport as possible. If alignment
is 0.5, the child must be
positioned as close to the center of the viewport as possible.
The target
might not be a direct child of this viewport but it must be a
descendant of the viewport. Other viewports in between this viewport and
the target
will not be adjusted.
This method assumes that the content of the viewport moves linearly, i.e.
when the offset of the viewport is changed by x then target
also moves
by x within the viewport.
The optional Axis is used by
RenderTwoDimensionalViewport.getOffsetToReveal to
determine which of the two axes to compute an offset for. One dimensional
subclasses like RenderViewportBase and RenderListWheelViewport
will ignore the axis
value if provided, since there is only one Axis.
If the axis
is omitted when called on RenderTwoDimensionalViewport,
the RenderTwoDimensionalViewport.mainAxis
is used. To reveal an object
properly in both axes, this method should be called for each Axis as the
returned RevealedOffset.offset only represents the offset of one of the
the two ScrollPositions.
See also:
- RevealedOffset, which describes the return value of this method.
Implementation
@protected
@override
RevealedOffset getOffsetToReveal(
RenderObject target,
double alignment, {
Rect? rect,
Axis? axis,
}) {
// If an axis has not been specified, use the mainAxis.
axis ??= mainAxis;
final (double offset, AxisDirection axisDirection) = switch (axis) {
Axis.vertical => (verticalOffset.pixels, verticalAxisDirection),
Axis.horizontal => (horizontalOffset.pixels, horizontalAxisDirection),
};
rect ??= target.paintBounds;
// `child` will be the last RenderObject before the viewport when walking
// up from `target`.
RenderObject child = target;
while (child.parent != this) {
child = child.parent!;
}
assert(child.parent == this);
final RenderBox box = child as RenderBox;
final Rect rectLocal = MatrixUtils.transformRect(target.getTransformTo(child), rect);
double leadingScrollOffset = offset;
// The scroll offset of `rect` within `child`.
leadingScrollOffset += switch (axisDirection) {
AxisDirection.up => child.size.height - rectLocal.bottom,
AxisDirection.left => child.size.width - rectLocal.right,
AxisDirection.right => rectLocal.left,
AxisDirection.down => rectLocal.top,
};
// The scroll offset in the viewport to `rect`.
final Offset paintOffset = parentDataOf(box).paintOffset!;
leadingScrollOffset += switch (axisDirection) {
AxisDirection.up => viewportDimension.height - paintOffset.dy - box.size.height,
AxisDirection.left => viewportDimension.width - paintOffset.dx - box.size.width,
AxisDirection.right => paintOffset.dx,
AxisDirection.down => paintOffset.dy,
};
// This step assumes the viewport's layout is up-to-date, i.e., if
// the position is changed after the last performLayout, the new scroll
// position will not be accounted for.
final Matrix4 transform = target.getTransformTo(this);
Rect targetRect = MatrixUtils.transformRect(transform, rect);
final double mainAxisExtentDifference = switch (axis) {
Axis.horizontal => viewportDimension.width - rectLocal.width,
Axis.vertical => viewportDimension.height - rectLocal.height,
};
final double targetOffset = leadingScrollOffset - mainAxisExtentDifference * alignment;
final double offsetDifference = switch (axis) {
Axis.horizontal => horizontalOffset.pixels - targetOffset,
Axis.vertical => verticalOffset.pixels - targetOffset,
};
targetRect = switch (axisDirection) {
AxisDirection.up => targetRect.translate(0.0, -offsetDifference),
AxisDirection.down => targetRect.translate(0.0, offsetDifference),
AxisDirection.left => targetRect.translate(-offsetDifference, 0.0),
AxisDirection.right => targetRect.translate( offsetDifference, 0.0),
};
final RevealedOffset revealedOffset = RevealedOffset(
offset: targetOffset,
rect: targetRect,
);
return revealedOffset;
}