Unverified Commit c4d6311a authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

Fix #16464

* Fix #16464: Pass hit test when a big child is inside RenderFittedBox, RenderTransform, RenderFractionalTranslation, or RenderFollowerLayer

* Override `hitTestChildren`

* RenderTransform and RenderFollowerLayer shouldn't check if they are hit
themselves

* Test the hit test for translated child into translated box

* Add hit test for `FractionalTranslation`

* Don't check if RenderFractionalTranslation is hit themself

* Add hit test for FractionalTranslation

* Add test for FractionalTranslation
parent 677df7c3
......@@ -2074,6 +2074,15 @@ class RenderTransform extends RenderProxyBox {
@override
bool hitTest(HitTestResult result, { Offset position }) {
// RenderTransform objects don't check if they are
// themselves hit, because it's confusing to think about
// how the untransformed size and the child's transformed
// position interact.
return hitTestChildren(result, position: position);
}
@override
bool hitTestChildren(HitTestResult result, { Offset position }) {
if (transformHitTests) {
final Matrix4 inverse = Matrix4.tryInvert(_effectiveTransform);
if (inverse == null) {
......@@ -2083,7 +2092,7 @@ class RenderTransform extends RenderProxyBox {
}
position = MatrixUtils.transformPoint(inverse, position);
}
return super.hitTest(result, position: position);
return super.hitTestChildren(result, position: position);
}
@override
......@@ -2254,7 +2263,7 @@ class RenderFittedBox extends RenderProxyBox {
}
@override
bool hitTest(HitTestResult result, { Offset position }) {
bool hitTestChildren(HitTestResult result, { Offset position }) {
if (size.isEmpty)
return false;
_updatePaintData();
......@@ -2265,7 +2274,7 @@ class RenderFittedBox extends RenderProxyBox {
return false;
}
position = MatrixUtils.transformPoint(inverse, position);
return super.hitTest(result, position: position);
return super.hitTestChildren(result, position: position);
}
@override
......@@ -2322,6 +2331,15 @@ class RenderFractionalTranslation extends RenderProxyBox {
markNeedsPaint();
}
@override
bool hitTest(HitTestResult result, { Offset position }) {
// RenderFractionalTranslation objects don't check if they are
// themselves hit, because it's confusing to think about
// how the untransformed size and the child's transformed
// position interact.
return hitTestChildren(result, position: position);
}
/// When set to true, hit tests are performed based on the position of the
/// child as it is painted. When set to false, hit tests are performed
/// ignoring the transformation.
......@@ -2331,7 +2349,7 @@ class RenderFractionalTranslation extends RenderProxyBox {
bool transformHitTests;
@override
bool hitTest(HitTestResult result, { Offset position }) {
bool hitTestChildren(HitTestResult result, { Offset position }) {
assert(!debugNeedsLayout);
if (transformHitTests) {
position = new Offset(
......@@ -2339,7 +2357,7 @@ class RenderFractionalTranslation extends RenderProxyBox {
position.dy - translation.dy * size.height,
);
}
return super.hitTest(result, position: position);
return super.hitTestChildren(result, position: position);
}
@override
......@@ -4174,6 +4192,15 @@ class RenderFollowerLayer extends RenderProxyBox {
@override
bool hitTest(HitTestResult result, { Offset position }) {
// RenderFollowerLayer objects don't check if they are
// themselves hit, because it's confusing to think about
// how the untransformed size and the child's transformed
// position interact.
return hitTestChildren(result, position: position);
}
@override
bool hitTestChildren(HitTestResult result, { Offset position }) {
final Matrix4 inverse = Matrix4.tryInvert(getCurrentTransform());
if (inverse == null) {
// We cannot invert the effective transform. That means the child
......@@ -4181,7 +4208,7 @@ class RenderFollowerLayer extends RenderProxyBox {
return false;
}
position = MatrixUtils.transformPoint(inverse, position);
return super.hitTest(result, position: position);
return super.hitTestChildren(result, position: position);
}
@override
......
......@@ -54,6 +54,97 @@ void main() {
});
group('FractionalTranslation', () {
testWidgets('hit test - entirely inside the bounding box', (WidgetTester tester) async {
final GlobalKey key1 = new GlobalKey();
bool _pointerDown = false;
await tester.pumpWidget(
new Center(
child: new FractionalTranslation(
translation: Offset.zero,
transformHitTests: true,
child: new Listener(
onPointerDown: (PointerDownEvent event) {
_pointerDown = true;
},
child: new SizedBox(
key: key1,
width: 100.0,
height: 100.0,
child: new Container(
color: const Color(0xFF0000FF)
),
),
)
)
)
);
expect(_pointerDown, isFalse);
await tester.tap(find.byKey(key1));
expect(_pointerDown, isTrue);
});
testWidgets('hit test - partially inside the bounding box', (WidgetTester tester) async {
final GlobalKey key1 = new GlobalKey();
bool _pointerDown = false;
await tester.pumpWidget(
new Center(
child: new FractionalTranslation(
translation: const Offset(0.5, 0.5),
transformHitTests: true,
child: new Listener(
onPointerDown: (PointerDownEvent event) {
_pointerDown = true;
},
child: new SizedBox(
key: key1,
width: 100.0,
height: 100.0,
child: new Container(
color: const Color(0xFF0000FF)
),
),
)
)
)
);
expect(_pointerDown, isFalse);
await tester.tap(find.byKey(key1));
expect(_pointerDown, isTrue);
});
testWidgets('hit test - completely outside the bounding box', (WidgetTester tester) async {
final GlobalKey key1 = new GlobalKey();
bool _pointerDown = false;
await tester.pumpWidget(
new Center(
child: new FractionalTranslation(
translation: const Offset(1.0, 1.0),
transformHitTests: true,
child: new Listener(
onPointerDown: (PointerDownEvent event) {
_pointerDown = true;
},
child: new SizedBox(
key: key1,
width: 100.0,
height: 100.0,
child: new Container(
color: const Color(0xFF0000FF)
),
),
)
)
)
);
expect(_pointerDown, isFalse);
await tester.tap(find.byKey(key1));
expect(_pointerDown, isTrue);
});
});
}
HitsRenderBox hits(RenderBox renderBox) => new HitsRenderBox(renderBox);
......
......@@ -439,6 +439,39 @@ void main() {
}
}
});
testWidgets('Big child into small fitted box - hit testing', (WidgetTester tester) async {
final GlobalKey key1 = new GlobalKey();
bool _pointerDown = false;
await tester.pumpWidget(
new Center(
child: new SizedBox(
width: 100.0,
height: 100.0,
child: new FittedBox(
fit: BoxFit.contain,
alignment: FractionalOffset.center,
child: new SizedBox(
width: 1000.0,
height: 1000.0,
child: new Listener(
onPointerDown: (PointerDownEvent event) {
_pointerDown = true;
},
child: new Container(
key: key1,
color: const Color(0xFF000000),
)
)
)
)
)
)
);
expect(_pointerDown, isFalse);
await tester.tap(find.byKey(key1));
expect(_pointerDown, isTrue);
});
}
List<Type> getLayers() {
......
......@@ -333,4 +333,29 @@ void main() {
-400.0, -300.0, 0.0, 1.0, // it's 1600x1200, centered in an 800x600 square
]);
});
testWidgets('Translated child into translated box - hit test', (WidgetTester tester) async {
final GlobalKey key1 = new GlobalKey();
bool _pointerDown = false;
await tester.pumpWidget(
new Transform.translate(
offset: const Offset(100.0, 50.0),
child: new Transform.translate(
offset: const Offset(1000.0, 1000.0),
child: new Listener(
onPointerDown: (PointerDownEvent event) {
_pointerDown = true;
},
child: new Container(
key: key1,
color: const Color(0xFF000000),
)
)
)
),
);
expect(_pointerDown, isFalse);
await tester.tap(find.byKey(key1));
expect(_pointerDown, isTrue);
});
}
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