Unverified Commit 0fd75528 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Reland InteractiveViewer.builder (#79287)

parent 625be62a
......@@ -1161,6 +1161,89 @@ void main() {
findsOneWidget,
);
});
testWidgets('builder can change widgets that are off-screen', (WidgetTester tester) async {
final TransformationController transformationController = TransformationController();
const double childHeight = 10.0;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(
height: 50.0,
child: InteractiveViewer.builder(
transformationController: transformationController,
scaleEnabled: false,
boundaryMargin: const EdgeInsets.all(double.infinity),
// Build visible children green, off-screen children red.
builder: (BuildContext context, Quad viewportQuad) {
final Rect viewport = _axisAlignedBoundingBox(viewportQuad);
final List<Container> children = <Container>[];
for (int i = 0; i < 10; i++) {
final double childTop = i * childHeight;
final double childBottom = childTop + childHeight;
final bool visible = (childBottom >= viewport.top && childBottom <= viewport.bottom)
|| (childTop >= viewport.top && childTop <= viewport.bottom);
children.add(Container(
height: childHeight,
color: visible ? Colors.green : Colors.red,
));
}
return Column(
children: children,
);
},
),
),
),
),
),
);
expect(transformationController.value, equals(Matrix4.identity()));
// The first six are partially visible and therefore green.
int i = 0;
for (final Element element in find.byType(Container, skipOffstage: false).evaluate()) {
final Container container = element.widget as Container;
if (i < 6) {
expect(container.color, Colors.green);
} else {
expect(container.color, Colors.red);
}
i++;
}
// Drag to pan down past the first child.
final Offset childOffset = tester.getTopLeft(find.byType(SizedBox));
const double translationY = 15.0;
final Offset childInterior = Offset(
childOffset.dx,
childOffset.dy + translationY,
);
final TestGesture gesture = await tester.startGesture(childInterior);
addTearDown(gesture.removePointer);
await tester.pump();
await gesture.moveTo(childOffset);
await tester.pump();
await gesture.up();
await tester.pumpAndSettle();
expect(transformationController.value, isNot(Matrix4.identity()));
expect(transformationController.value.getTranslation().y, -translationY);
// After scrolling down a bit, the first child is not visible, the next
// six are, and the final three are not.
i = 0;
for (final Element element in find.byType(Container, skipOffstage: false).evaluate()) {
final Container container = element.widget as Container;
if (i > 0 && i < 7) {
expect(container.color, Colors.green);
} else {
expect(container.color, Colors.red);
}
i++;
}
});
});
group('getNearestPointOnLine', () {
......@@ -1370,3 +1453,27 @@ void main() {
});
});
}
// Returns the axis aligned bounding box for the given Quad, which might not
// be axis aligned.
Rect _axisAlignedBoundingBox(Quad quad) {
double? xMin;
double? xMax;
double? yMin;
double? yMax;
for (final Vector3 point in <Vector3>[quad.point0, quad.point1, quad.point2, quad.point3]) {
if (xMin == null || point.x < xMin) {
xMin = point.x;
}
if (xMax == null || point.x > xMax) {
xMax = point.x;
}
if (yMin == null || point.y < yMin) {
yMin = point.y;
}
if (yMax == null || point.y > yMax) {
yMax = point.y;
}
}
return Rect.fromLTRB(xMin!, yMin!, xMax!, yMax!);
}
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