Commit 6ddd0bb4 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Make ensureVisible work with sliver-based viewports (#7920)

There appears to be an issue with children before the center widget.
I've filled a bug about that issue and will follow up in a later patch.
parent 474c2c7d
......@@ -1117,7 +1117,7 @@ abstract class RenderAbstractViewport implements RenderObject {
return null;
}
double getOffsetToReveal(RenderObject descendant, double alignment);
double getOffsetToReveal(RenderObject target, double alignment);
}
// ///
......@@ -1339,9 +1339,83 @@ abstract class RenderViewportBase2<ParentDataClass extends ContainerParentDataMi
}
@override
double getOffsetToReveal(RenderObject descendant, double alignment) {
// TODO(abath): Implement this function for sliver-based viewports.
return 0.0;
double getOffsetToReveal(RenderObject target, double alignment) {
double leadingScrollOffset;
double targetMainAxisExtent;
RenderObject descendant;
if (target is RenderBox) {
final RenderBox targetBox = target;
RenderBox pivot = targetBox;
while (pivot.parent is RenderBox)
pivot = pivot.parent;
assert(pivot.parent != null);
assert(pivot.parent != this);
assert(pivot != this);
final Matrix4 transform = targetBox.getTransformTo(pivot);
final Rect bounds = MatrixUtils.transformRect(transform, targetBox.paintBounds);
target = pivot;
// TODO(abarth): Support other kinds of render objects besides slivers.
assert(target.parent is RenderSliver);
final RenderSliver pivotParent = target.parent;
final GrowthDirection growthDirection = pivotParent.constraints.growthDirection;
switch (applyGrowthDirectionToAxisDirection(axisDirection, growthDirection)) {
case AxisDirection.up:
leadingScrollOffset = pivot.size.height - bounds.bottom;
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:
leadingScrollOffset = pivot.size.width - bounds.right;
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 offset.pixels;
}
// 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;
leadingScrollOffset = scrollOffsetOf(sliver, leadingScrollOffset);
double mainAxisExtent;
switch (axis) {
case Axis.horizontal:
mainAxisExtent = size.width;
break;
case Axis.vertical:
mainAxisExtent = size.height;
break;
}
return leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment;
}
@protected
......@@ -1408,6 +1482,9 @@ abstract class RenderViewportBase2<ParentDataClass extends ContainerParentDataMi
@protected
Offset paintOffsetOf(RenderSliver child);
@protected
double scrollOffsetOf(RenderSliver child, double scrollOffset);
// applyPaintTransform
/// Converts the `parentMainAxisPosition` into the child's coordinate system.
......@@ -1692,6 +1769,32 @@ class RenderViewport2 extends RenderViewportBase2<SliverPhysicalContainerParentD
return childParentData.paintOffset;
}
@override
double scrollOffsetOf(RenderSliver child, double scrollOffsetWithinChild) {
assert(child.parent == this);
final GrowthDirection growthDirection = child.constraints.growthDirection;
assert(growthDirection != null);
switch (growthDirection) {
case GrowthDirection.forward:
double scrollOffsetToChild = 0.0;
RenderSliver current = center;
while (current != child) {
scrollOffsetToChild += current.geometry.scrollExtent;
current = childAfter(current);
}
return scrollOffsetToChild + scrollOffsetWithinChild;
case GrowthDirection.reverse:
double scrollOffsetToChild = 0.0;
RenderSliver current = childBefore(center);
while (current != child) {
scrollOffsetToChild -= current.geometry.scrollExtent;
current = childBefore(current);
}
return scrollOffsetToChild - scrollOffsetWithinChild;
}
return null;
}
@override
void applyPaintTransform(RenderObject child, Matrix4 transform) {
assert(child != null);
......@@ -1949,6 +2052,19 @@ class RenderShrinkWrappingViewport extends RenderViewportBase2<SliverLogicalCont
return computeAbsolutePaintOffset(child, childParentData.layoutOffset, GrowthDirection.forward);
}
@override
double scrollOffsetOf(RenderSliver child, double scrollOffsetWithinChild) {
assert(child.parent == this);
assert(child.constraints.growthDirection == GrowthDirection.forward);
double scrollOffsetToChild = 0.0;
RenderSliver current = firstChild;
while (current != child) {
scrollOffsetToChild += current.geometry.scrollExtent;
current = childAfter(current);
}
return scrollOffsetToChild + scrollOffsetWithinChild;
}
@override
void applyPaintTransform(RenderObject child, Matrix4 transform) {
assert(child != null);
......
......@@ -199,7 +199,6 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
return null;
}
double get _minScrollExtent {
assert(hasSize);
return 0.0;
......@@ -334,44 +333,43 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix
}
@override
double getOffsetToReveal(RenderObject descendant, double alignment) {
if (descendant is! RenderBox)
double getOffsetToReveal(RenderObject target, double alignment) {
if (target is! RenderBox)
return offset.pixels;
final RenderBox target = descendant;
final Matrix4 transform = target.getTransformTo(this);
final Rect bounds = MatrixUtils.transformRect(transform, target.paintBounds);
final RenderBox targetBox = target;
final Matrix4 transform = targetBox.getTransformTo(this);
final Rect bounds = MatrixUtils.transformRect(transform, targetBox.paintBounds);
final Size contentSize = child.size;
double leading;
double trailing;
double viewportExtent;
double leadingScrollOffset;
double targetMainAxisExtent;
double mainAxisExtent;
assert(axisDirection != null);
switch (axisDirection) {
case AxisDirection.up:
viewportExtent = size.height;
leading = contentSize.height - bounds.bottom;
trailing = contentSize.height - bounds.top;
mainAxisExtent = size.height;
leadingScrollOffset = contentSize.height - bounds.bottom;
targetMainAxisExtent = bounds.height;
break;
case AxisDirection.right:
viewportExtent = size.width;
leading = bounds.left;
trailing = bounds.right;
mainAxisExtent = size.width;
leadingScrollOffset = bounds.left;
targetMainAxisExtent = bounds.width;
break;
case AxisDirection.down:
viewportExtent = size.height;
leading = bounds.top;
trailing = bounds.bottom;
mainAxisExtent = size.height;
leadingScrollOffset = bounds.top;
targetMainAxisExtent = bounds.height;
break;
case AxisDirection.left:
viewportExtent = size.width;
leading = contentSize.width - bounds.right;
trailing = contentSize.width - bounds.left;
mainAxisExtent = size.width;
leadingScrollOffset = contentSize.width - bounds.right;
targetMainAxisExtent = bounds.width;
break;
}
final double targetExtent = trailing - leading;
return leading - (viewportExtent - targetExtent) * alignment;
return leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment