Skip to content

Commit e5beafa

Browse files
authored
Expose ignoringPointer property for Draggable and LongPressDraggable (flutter#100475)
1 parent 5bb6b07 commit e5beafa

File tree

2 files changed

+112
-1
lines changed

2 files changed

+112
-1
lines changed

packages/flutter/lib/src/widgets/drag_target.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ enum DragAnchor {
154154
/// user lifts their finger while on top of a [DragTarget], that target is given
155155
/// the opportunity to accept the [data] carried by the draggable.
156156
///
157+
/// The [ignoringFeedbackPointer] defaults to true, which means that
158+
/// the [feedback] widget ignores the pointer during hit testing. Similarly,
159+
/// [ignoringFeedbackSemantics] defaults to true, and the [feedback] also ignores
160+
/// semantics when building the semantics tree.
161+
///
157162
/// On multitouch devices, multiple drags can occur simultaneously because there
158163
/// can be multiple pointers in contact with the device at once. To limit the
159164
/// number of simultaneous drags, use the [maxSimultaneousDrags] property. The
@@ -207,11 +212,13 @@ class Draggable<T extends Object> extends StatefulWidget {
207212
this.onDragEnd,
208213
this.onDragCompleted,
209214
this.ignoringFeedbackSemantics = true,
215+
this.ignoringFeedbackPointer = true,
210216
this.rootOverlay = false,
211217
this.hitTestBehavior = HitTestBehavior.deferToChild,
212218
}) : assert(child != null),
213219
assert(feedback != null),
214220
assert(ignoringFeedbackSemantics != null),
221+
assert(ignoringFeedbackPointer != null),
215222
assert(maxSimultaneousDrags == null || maxSimultaneousDrags >= 0);
216223

217224
/// The data that will be dropped by this draggable.
@@ -310,6 +317,14 @@ class Draggable<T extends Object> extends StatefulWidget {
310317
/// Defaults to true.
311318
final bool ignoringFeedbackSemantics;
312319

320+
/// Whether the [feedback] widget is ignored during hit testing.
321+
///
322+
/// Regardless of whether this widget is ignored during hit testing, it will
323+
/// still consume space during layout and be visible during painting.
324+
///
325+
/// Defaults to true.
326+
final bool ignoringFeedbackPointer;
327+
313328
/// Controls how this widget competes with other gestures to initiate a drag.
314329
///
315330
/// If affinity is null, this widget initiates a drag as soon as it recognizes
@@ -447,6 +462,7 @@ class LongPressDraggable<T extends Object> extends Draggable<T> {
447462
super.onDragCompleted,
448463
this.hapticFeedbackOnStart = true,
449464
super.ignoringFeedbackSemantics,
465+
super.ignoringFeedbackPointer,
450466
this.delay = kLongPressTimeout,
451467
});
452468

@@ -542,6 +558,7 @@ class _DraggableState<T extends Object> extends State<Draggable<T>> {
542558
feedback: widget.feedback,
543559
feedbackOffset: widget.feedbackOffset,
544560
ignoringFeedbackSemantics: widget.ignoringFeedbackSemantics,
561+
ignoringFeedbackPointer: widget.ignoringFeedbackPointer,
545562
onDragUpdate: (DragUpdateDetails details) {
546563
if (mounted && widget.onDragUpdate != null) {
547564
widget.onDragUpdate!(details);
@@ -796,8 +813,10 @@ class _DragAvatar<T extends Object> extends Drag {
796813
this.onDragUpdate,
797814
this.onDragEnd,
798815
required this.ignoringFeedbackSemantics,
816+
required this.ignoringFeedbackPointer,
799817
}) : assert(overlayState != null),
800818
assert(ignoringFeedbackSemantics != null),
819+
assert(ignoringFeedbackPointer != null),
801820
assert(dragStartPoint != null),
802821
assert(feedbackOffset != null),
803822
_position = initialPosition {
@@ -815,6 +834,7 @@ class _DragAvatar<T extends Object> extends Drag {
815834
final _OnDragEnd? onDragEnd;
816835
final OverlayState overlayState;
817836
final bool ignoringFeedbackSemantics;
837+
final bool ignoringFeedbackPointer;
818838

819839
_DragTargetState<Object>? _activeTarget;
820840
final List<_DragTargetState<Object>> _enteredTargets = <_DragTargetState<Object>>[];
@@ -937,6 +957,7 @@ class _DragAvatar<T extends Object> extends Drag {
937957
left: _lastOffset!.dx - overlayTopLeft.dx,
938958
top: _lastOffset!.dy - overlayTopLeft.dy,
939959
child: IgnorePointer(
960+
ignoring: ignoringFeedbackPointer,
940961
ignoringSemantics: ignoringFeedbackSemantics,
941962
child: feedback,
942963
),

packages/flutter/test/widgets/draggable_test.dart

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import 'package:flutter/gestures.dart';
1212
import 'package:flutter/material.dart';
13-
import 'package:flutter/semantics.dart';
13+
import 'package:flutter/rendering.dart';
1414
import 'package:flutter/services.dart';
1515
import 'package:flutter_test/flutter_test.dart';
1616

@@ -3074,6 +3074,96 @@ void main() {
30743074
expect(tester.widget<Listener>(find.byType(Listener).first).behavior, hitTestBehavior);
30753075
});
30763076

3077+
// Regression test for https://github.com/flutter/flutter/issues/92083
3078+
testWidgets('feedback respect the MouseRegion cursor configure', (WidgetTester tester) async {
3079+
await tester.pumpWidget(
3080+
MaterialApp(
3081+
home: Column(
3082+
children: const <Widget>[
3083+
Draggable<int>(
3084+
ignoringFeedbackPointer: false,
3085+
feedback: MouseRegion(
3086+
cursor: SystemMouseCursors.grabbing,
3087+
child: SizedBox(height: 50.0, child: Text('Draggable')),
3088+
),
3089+
child: SizedBox(height: 50.0, child: Text('Target')),
3090+
),
3091+
],
3092+
),
3093+
),
3094+
);
3095+
3096+
final Offset location = tester.getCenter(find.text('Target'));
3097+
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
3098+
await gesture.addPointer(location: location);
3099+
addTearDown(gesture.removePointer);
3100+
3101+
await gesture.down(location);
3102+
await tester.pump();
3103+
3104+
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grabbing);
3105+
});
3106+
3107+
testWidgets('configurable feedback ignore pointer behavior', (WidgetTester tester) async {
3108+
bool onTap = false;
3109+
await tester.pumpWidget(
3110+
MaterialApp(
3111+
home: Column(
3112+
children: <Widget>[
3113+
Draggable<int>(
3114+
ignoringFeedbackPointer: false,
3115+
feedback: GestureDetector(
3116+
onTap: () => onTap = true,
3117+
child: const SizedBox(height: 50.0, child: Text('Draggable')),
3118+
),
3119+
child: const SizedBox(height: 50.0, child: Text('Target')),
3120+
),
3121+
],
3122+
),
3123+
),
3124+
);
3125+
3126+
final Offset location = tester.getCenter(find.text('Target'));
3127+
final TestGesture gesture = await tester.startGesture(location, pointer: 7);
3128+
final Offset secondLocation = location + const Offset(7.0, 7.0);
3129+
await gesture.moveTo(secondLocation);
3130+
await tester.pump();
3131+
3132+
await tester.tap(find.text('Draggable'));
3133+
expect(onTap, true);
3134+
});
3135+
3136+
testWidgets('configurable feedback ignore pointer behavior - LongPressDraggable', (WidgetTester tester) async {
3137+
bool onTap = false;
3138+
await tester.pumpWidget(
3139+
MaterialApp(
3140+
home: Column(
3141+
children: <Widget>[
3142+
LongPressDraggable<int>(
3143+
ignoringFeedbackPointer: false,
3144+
feedback: GestureDetector(
3145+
onTap: () => onTap = true,
3146+
child: const SizedBox(height: 50.0, child: Text('Draggable')),
3147+
),
3148+
child: const SizedBox(height: 50.0, child: Text('Target')),
3149+
),
3150+
],
3151+
),
3152+
),
3153+
);
3154+
3155+
final Offset location = tester.getCenter(find.text('Target'));
3156+
final TestGesture gesture = await tester.startGesture(location, pointer: 7);
3157+
await tester.pump(kLongPressTimeout);
3158+
3159+
final Offset secondLocation = location + const Offset(7.0, 7.0);
3160+
await gesture.moveTo(secondLocation);
3161+
await tester.pump();
3162+
3163+
await tester.tap(find.text('Draggable'));
3164+
expect(onTap, true);
3165+
});
3166+
30773167
testWidgets('configurable DragTarget hit test behavior', (WidgetTester tester) async {
30783168
const HitTestBehavior hitTestBehavior = HitTestBehavior.deferToChild;
30793169

0 commit comments

Comments
 (0)