Unverified Commit a8e41f82 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Fix InteractiveViewer.builder for custom RenderBox parents (#80166)

parent a27815c1
......@@ -1161,6 +1161,124 @@ 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++;
}
});
// Accessing the intrinsic size of a LayoutBuilder throws an error, so
// InteractiveViewer only uses a LayoutBuilder when it's needed by
// InteractiveViewer.builder.
testWidgets('LayoutBuilder is only used for InteractiveViewer.builder', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: InteractiveViewer(
child: const SizedBox(width: 200.0, height: 200.0),
),
),
),
),
);
expect(find.byType(LayoutBuilder), findsNothing);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: InteractiveViewer.builder(
builder: (BuildContext context, Quad viewport) {
return const SizedBox(width: 200.0, height: 200.0);
},
),
),
),
),
);
expect(find.byType(LayoutBuilder), findsOneWidget);
});
});
group('getNearestPointOnLine', () {
......@@ -1370,3 +1488,25 @@ void main() {
});
});
}
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