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

Expose `ignoringPointer` property for `Draggable` and `LongPressDraggable` (#100475)

parent 5bb6b071
......@@ -154,6 +154,11 @@ enum DragAnchor {
/// user lifts their finger while on top of a [DragTarget], that target is given
/// the opportunity to accept the [data] carried by the draggable.
///
/// The [ignoringFeedbackPointer] defaults to true, which means that
/// the [feedback] widget ignores the pointer during hit testing. Similarly,
/// [ignoringFeedbackSemantics] defaults to true, and the [feedback] also ignores
/// semantics when building the semantics tree.
///
/// On multitouch devices, multiple drags can occur simultaneously because there
/// can be multiple pointers in contact with the device at once. To limit the
/// number of simultaneous drags, use the [maxSimultaneousDrags] property. The
......@@ -207,11 +212,13 @@ class Draggable<T extends Object> extends StatefulWidget {
this.onDragEnd,
this.onDragCompleted,
this.ignoringFeedbackSemantics = true,
this.ignoringFeedbackPointer = true,
this.rootOverlay = false,
this.hitTestBehavior = HitTestBehavior.deferToChild,
}) : assert(child != null),
assert(feedback != null),
assert(ignoringFeedbackSemantics != null),
assert(ignoringFeedbackPointer != null),
assert(maxSimultaneousDrags == null || maxSimultaneousDrags >= 0);
/// The data that will be dropped by this draggable.
......@@ -310,6 +317,14 @@ class Draggable<T extends Object> extends StatefulWidget {
/// Defaults to true.
final bool ignoringFeedbackSemantics;
/// Whether the [feedback] widget is ignored during hit testing.
///
/// Regardless of whether this widget is ignored during hit testing, it will
/// still consume space during layout and be visible during painting.
///
/// Defaults to true.
final bool ignoringFeedbackPointer;
/// Controls how this widget competes with other gestures to initiate a drag.
///
/// 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> {
super.onDragCompleted,
this.hapticFeedbackOnStart = true,
super.ignoringFeedbackSemantics,
super.ignoringFeedbackPointer,
this.delay = kLongPressTimeout,
});
......@@ -542,6 +558,7 @@ class _DraggableState<T extends Object> extends State<Draggable<T>> {
feedback: widget.feedback,
feedbackOffset: widget.feedbackOffset,
ignoringFeedbackSemantics: widget.ignoringFeedbackSemantics,
ignoringFeedbackPointer: widget.ignoringFeedbackPointer,
onDragUpdate: (DragUpdateDetails details) {
if (mounted && widget.onDragUpdate != null) {
widget.onDragUpdate!(details);
......@@ -796,8 +813,10 @@ class _DragAvatar<T extends Object> extends Drag {
this.onDragUpdate,
this.onDragEnd,
required this.ignoringFeedbackSemantics,
required this.ignoringFeedbackPointer,
}) : assert(overlayState != null),
assert(ignoringFeedbackSemantics != null),
assert(ignoringFeedbackPointer != null),
assert(dragStartPoint != null),
assert(feedbackOffset != null),
_position = initialPosition {
......@@ -815,6 +834,7 @@ class _DragAvatar<T extends Object> extends Drag {
final _OnDragEnd? onDragEnd;
final OverlayState overlayState;
final bool ignoringFeedbackSemantics;
final bool ignoringFeedbackPointer;
_DragTargetState<Object>? _activeTarget;
final List<_DragTargetState<Object>> _enteredTargets = <_DragTargetState<Object>>[];
......@@ -937,6 +957,7 @@ class _DragAvatar<T extends Object> extends Drag {
left: _lastOffset!.dx - overlayTopLeft.dx,
top: _lastOffset!.dy - overlayTopLeft.dy,
child: IgnorePointer(
ignoring: ignoringFeedbackPointer,
ignoringSemantics: ignoringFeedbackSemantics,
child: feedback,
),
......
......@@ -10,7 +10,7 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
......@@ -3074,6 +3074,96 @@ void main() {
expect(tester.widget<Listener>(find.byType(Listener).first).behavior, hitTestBehavior);
});
// Regression test for https://github.com/flutter/flutter/issues/92083
testWidgets('feedback respect the MouseRegion cursor configure', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
home: Column(
children: const <Widget>[
Draggable<int>(
ignoringFeedbackPointer: false,
feedback: MouseRegion(
cursor: SystemMouseCursors.grabbing,
child: SizedBox(height: 50.0, child: Text('Draggable')),
),
child: SizedBox(height: 50.0, child: Text('Target')),
),
],
),
),
);
final Offset location = tester.getCenter(find.text('Target'));
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer(location: location);
addTearDown(gesture.removePointer);
await gesture.down(location);
await tester.pump();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grabbing);
});
testWidgets('configurable feedback ignore pointer behavior', (WidgetTester tester) async {
bool onTap = false;
await tester.pumpWidget(
MaterialApp(
home: Column(
children: <Widget>[
Draggable<int>(
ignoringFeedbackPointer: false,
feedback: GestureDetector(
onTap: () => onTap = true,
child: const SizedBox(height: 50.0, child: Text('Draggable')),
),
child: const SizedBox(height: 50.0, child: Text('Target')),
),
],
),
),
);
final Offset location = tester.getCenter(find.text('Target'));
final TestGesture gesture = await tester.startGesture(location, pointer: 7);
final Offset secondLocation = location + const Offset(7.0, 7.0);
await gesture.moveTo(secondLocation);
await tester.pump();
await tester.tap(find.text('Draggable'));
expect(onTap, true);
});
testWidgets('configurable feedback ignore pointer behavior - LongPressDraggable', (WidgetTester tester) async {
bool onTap = false;
await tester.pumpWidget(
MaterialApp(
home: Column(
children: <Widget>[
LongPressDraggable<int>(
ignoringFeedbackPointer: false,
feedback: GestureDetector(
onTap: () => onTap = true,
child: const SizedBox(height: 50.0, child: Text('Draggable')),
),
child: const SizedBox(height: 50.0, child: Text('Target')),
),
],
),
),
);
final Offset location = tester.getCenter(find.text('Target'));
final TestGesture gesture = await tester.startGesture(location, pointer: 7);
await tester.pump(kLongPressTimeout);
final Offset secondLocation = location + const Offset(7.0, 7.0);
await gesture.moveTo(secondLocation);
await tester.pump();
await tester.tap(find.text('Draggable'));
expect(onTap, true);
});
testWidgets('configurable DragTarget hit test behavior', (WidgetTester tester) async {
const HitTestBehavior hitTestBehavior = HitTestBehavior.deferToChild;
......
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