Unverified Commit f1d8e30c authored by xubaolin's avatar xubaolin Committed by GitHub

Add `HitTestBehavior` property to `MouseRegion` (#100405)

parent 654ccf35
......@@ -2958,7 +2958,7 @@ class RenderPointerListener extends RenderProxyBoxWithHitTestBehavior {
///
/// * [MouseRegion], a widget that listens to hover events using
/// [RenderMouseRegion].
class RenderMouseRegion extends RenderProxyBox implements MouseTrackerAnnotation {
class RenderMouseRegion extends RenderProxyBoxWithHitTestBehavior implements MouseTrackerAnnotation {
/// Creates a render object that forwards pointer events to callbacks.
///
/// All parameters are optional. By default this method creates an opaque
......@@ -2972,16 +2972,13 @@ class RenderMouseRegion extends RenderProxyBox implements MouseTrackerAnnotation
bool validForMouseTracker = true,
bool opaque = true,
RenderBox? child,
HitTestBehavior? hitTestBehavior = HitTestBehavior.opaque,
}) : assert(opaque != null),
assert(cursor != null),
_cursor = cursor,
_validForMouseTracker = validForMouseTracker,
_opaque = opaque,
super(child);
@protected
@override
bool hitTestSelf(Offset position) => true;
super(behavior: hitTestBehavior ?? HitTestBehavior.opaque, child: child);
@override
bool hitTest(BoxHitTestResult result, { required Offset position }) {
......@@ -3019,6 +3016,19 @@ class RenderMouseRegion extends RenderProxyBox implements MouseTrackerAnnotation
}
}
/// How to behave during hit testing.
///
/// This defaults to [HitTestBehavior.opaque] if null.
HitTestBehavior? get hitTestBehavior => behavior;
set hitTestBehavior(HitTestBehavior? value) {
final HitTestBehavior newValue = value ?? HitTestBehavior.opaque;
if (behavior != newValue) {
behavior = newValue;
// Trigger [MouseTracker]'s device update to recalculate mouse states.
markNeedsPaint();
}
}
@override
PointerEnterEventListener? onEnter;
......
......@@ -6180,6 +6180,7 @@ class MouseRegion extends SingleChildRenderObjectWidget {
this.onHover,
this.cursor = MouseCursor.defer,
this.opaque = true,
this.hitTestBehavior,
Widget? child,
}) : assert(cursor != null),
assert(opaque != null),
......@@ -6330,6 +6331,11 @@ class MouseRegion extends SingleChildRenderObjectWidget {
/// This defaults to true.
final bool opaque;
/// How to behave during hit testing.
///
/// This defaults to [HitTestBehavior.opaque] if null.
final HitTestBehavior? hitTestBehavior;
@override
RenderMouseRegion createRenderObject(BuildContext context) {
return RenderMouseRegion(
......@@ -6338,6 +6344,7 @@ class MouseRegion extends SingleChildRenderObjectWidget {
onExit: onExit,
cursor: cursor,
opaque: opaque,
hitTestBehavior: hitTestBehavior,
);
}
......@@ -6348,7 +6355,8 @@ class MouseRegion extends SingleChildRenderObjectWidget {
..onHover = onHover
..onExit = onExit
..cursor = cursor
..opaque = opaque;
..opaque = opaque
..hitTestBehavior = hitTestBehavior;
}
@override
......
......@@ -76,6 +76,110 @@ class _HoverFeedbackState extends State<HoverFeedback> {
}
void main() {
// Regression test for https://github.com/flutter/flutter/issues/73330
testWidgets('hitTestBehavior test - HitTestBehavior.deferToChild/opaque', (WidgetTester tester) async {
bool onEnter = false;
await tester.pumpWidget(Center(
child: MouseRegion(
hitTestBehavior: HitTestBehavior.deferToChild,
onEnter: (_) => onEnter = true,
),
));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer(location: Offset.zero);
addTearDown(gesture.removePointer);
await tester.pump();
// The child is null, so `onEnter` does not trigger.
expect(onEnter, false);
// Update to the default value `HitTestBehavior.opaque`
await tester.pumpWidget(Center(
child: MouseRegion(
onEnter: (_) => onEnter = true,
),
));
expect(onEnter, true);
});
testWidgets('hitTestBehavior test - HitTestBehavior.deferToChild and non-opaque', (WidgetTester tester) async {
bool onEnterRegion1 = false;
bool onEnterRegion2 = false;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Stack(
children: <Widget>[
SizedBox(
width: 50.0,
height: 50.0,
child: MouseRegion(
onEnter: (_) => onEnterRegion1 = true,
),
),
SizedBox(
width: 50.0,
height: 50.0,
child: MouseRegion(
opaque: false,
hitTestBehavior: HitTestBehavior.deferToChild,
onEnter: (_) => onEnterRegion2 = true,
child: Container(
color: const Color.fromARGB(0xff, 0xff, 0x10, 0x19),
width: 50.0,
height: 50.0,
),
),
),
],
),
));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer(location: Offset.zero);
addTearDown(gesture.removePointer);
await tester.pump();
expect(onEnterRegion2, true);
expect(onEnterRegion1, true);
});
testWidgets('hitTestBehavior test - HitTestBehavior.translucent', (WidgetTester tester) async {
bool onEnterRegion1 = false;
bool onEnterRegion2 = false;
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Stack(
children: <Widget>[
SizedBox(
width: 50.0,
height: 50.0,
child: MouseRegion(
onEnter: (_) => onEnterRegion1 = true,
),
),
SizedBox(
width: 50.0,
height: 50.0,
child: MouseRegion(
hitTestBehavior: HitTestBehavior.translucent,
onEnter: (_) => onEnterRegion2 = true,
),
),
],
),
));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer(location: Offset.zero);
addTearDown(gesture.removePointer);
await tester.pump();
expect(onEnterRegion2, true);
expect(onEnterRegion1, true);
});
testWidgets('onEnter and onExit can be triggered with mouse buttons pressed', (WidgetTester tester) async {
PointerEnterEvent? enter;
PointerExitEvent? exit;
......@@ -1706,6 +1810,7 @@ void main() {
'parentData: MISSING',
'constraints: MISSING',
'size: MISSING',
'behavior: opaque',
'listeners: <none>',
]);
});
......@@ -1727,6 +1832,7 @@ void main() {
'parentData: MISSING',
'constraints: MISSING',
'size: MISSING',
'behavior: opaque',
'listeners: enter, hover, exit',
'cursor: SystemMouseCursor(click)',
'invalid for MouseTracker',
......
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