getOffsetToReveal method
- @override
Returns the offset that would be needed to reveal the target
RenderObject.
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 and there must not be any other RenderAbstractViewport objects between the target and this object.
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.
See also:
- RevealedOffset, which describes the return value of this method.
Implementation
@override
RevealedOffset getOffsetToReveal(RenderObject target, double alignment, {Rect rect}) {
double leadingScrollOffset;
double targetMainAxisExtent;
RenderObject descendant;
rect ??= target.paintBounds;
if (target is RenderBox) {
final RenderBox targetBox = target;
// The pivot will be the topmost child before we hit a RenderSliver.
RenderBox pivot = targetBox;
while (pivot.parent is RenderBox)
pivot = pivot.parent;
assert(pivot.parent != null);
assert(pivot.parent != this);
assert(pivot != this);
assert(pivot.parent is RenderSliver); // TODO(abarth): Support other kinds of render objects besides slivers.
final RenderSliver pivotParent = pivot.parent;
final Matrix4 transform = targetBox.getTransformTo(pivot);
final Rect bounds = MatrixUtils.transformRect(transform, rect);
final GrowthDirection growthDirection = pivotParent.constraints.growthDirection;
switch (applyGrowthDirectionToAxisDirection(axisDirection, growthDirection)) {
case AxisDirection.up:
double offset;
switch (growthDirection) {
case GrowthDirection.forward:
offset = bounds.bottom;
break;
case GrowthDirection.reverse:
offset = bounds.top;
break;
}
leadingScrollOffset = pivot.size.height - offset;
targetMainAxisExtent = bounds.height;
break;
case AxisDirection.right:
leadingScrollOffset = bounds.left;
targetMainAxisExtent = bounds.width;
break;
case AxisDirection.down:
leadingScrollOffset = bounds.top;
targetMainAxisExtent = bounds.height;
break;
case AxisDirection.left:
double offset;
switch (growthDirection) {
case GrowthDirection.forward:
offset = bounds.right;
break;
case GrowthDirection.reverse:
offset = bounds.left;
break;
}
leadingScrollOffset = pivot.size.width - offset;
targetMainAxisExtent = bounds.width;
break;
}
descendant = pivot;
} else if (target is RenderSliver) {
final RenderSliver targetSliver = target;
leadingScrollOffset = 0.0;
targetMainAxisExtent = targetSliver.geometry.scrollExtent;
descendant = targetSliver;
} else {
return RevealedOffset(offset: offset.pixels, rect: rect);
}
// The child will be the topmost object before we get to the viewport.
RenderObject child = descendant;
while (child.parent is RenderSliver) {
final RenderSliver parent = child.parent;
leadingScrollOffset += parent.childScrollOffset(child);
child = parent;
}
assert(child.parent == this);
assert(child is RenderSliver);
final RenderSliver sliver = child;
final double extentOfPinnedSlivers = maxScrollObstructionExtentBefore(sliver);
leadingScrollOffset = scrollOffsetOf(sliver, leadingScrollOffset);
switch (sliver.constraints.growthDirection) {
case GrowthDirection.forward:
leadingScrollOffset -= extentOfPinnedSlivers;
break;
case GrowthDirection.reverse:
// Nothing to do.
break;
}
double mainAxisExtent;
switch (axis) {
case Axis.horizontal:
mainAxisExtent = size.width - extentOfPinnedSlivers;
break;
case Axis.vertical:
mainAxisExtent = size.height - extentOfPinnedSlivers;
break;
}
final double targetOffset = leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment;
final double offsetDifference = offset.pixels - targetOffset;
final Matrix4 transform = target.getTransformTo(this);
applyPaintTransform(child, transform);
Rect targetRect = MatrixUtils.transformRect(transform, rect);
switch (axisDirection) {
case AxisDirection.down:
targetRect = targetRect.translate(0.0, offsetDifference);
break;
case AxisDirection.right:
targetRect = targetRect.translate(offsetDifference, 0.0);
break;
case AxisDirection.up:
targetRect = targetRect.translate(0.0, -offsetDifference);
break;
case AxisDirection.left:
targetRect = targetRect.translate(-offsetDifference, 0.0);
break;
}
return RevealedOffset(offset: targetOffset, rect: targetRect);
}