Expose ignoringPointer
property for Draggable
and LongPressDraggable
(#100475)
This commit is contained in:
parent
5bb6b07192
commit
e5beafaf36
@ -154,6 +154,11 @@ enum DragAnchor {
|
|||||||
/// user lifts their finger while on top of a [DragTarget], that target is given
|
/// 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 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
|
/// On multitouch devices, multiple drags can occur simultaneously because there
|
||||||
/// can be multiple pointers in contact with the device at once. To limit the
|
/// can be multiple pointers in contact with the device at once. To limit the
|
||||||
/// number of simultaneous drags, use the [maxSimultaneousDrags] property. The
|
/// number of simultaneous drags, use the [maxSimultaneousDrags] property. The
|
||||||
@ -207,11 +212,13 @@ class Draggable<T extends Object> extends StatefulWidget {
|
|||||||
this.onDragEnd,
|
this.onDragEnd,
|
||||||
this.onDragCompleted,
|
this.onDragCompleted,
|
||||||
this.ignoringFeedbackSemantics = true,
|
this.ignoringFeedbackSemantics = true,
|
||||||
|
this.ignoringFeedbackPointer = true,
|
||||||
this.rootOverlay = false,
|
this.rootOverlay = false,
|
||||||
this.hitTestBehavior = HitTestBehavior.deferToChild,
|
this.hitTestBehavior = HitTestBehavior.deferToChild,
|
||||||
}) : assert(child != null),
|
}) : assert(child != null),
|
||||||
assert(feedback != null),
|
assert(feedback != null),
|
||||||
assert(ignoringFeedbackSemantics != null),
|
assert(ignoringFeedbackSemantics != null),
|
||||||
|
assert(ignoringFeedbackPointer != null),
|
||||||
assert(maxSimultaneousDrags == null || maxSimultaneousDrags >= 0);
|
assert(maxSimultaneousDrags == null || maxSimultaneousDrags >= 0);
|
||||||
|
|
||||||
/// The data that will be dropped by this draggable.
|
/// The data that will be dropped by this draggable.
|
||||||
@ -310,6 +317,14 @@ class Draggable<T extends Object> extends StatefulWidget {
|
|||||||
/// Defaults to true.
|
/// Defaults to true.
|
||||||
final bool ignoringFeedbackSemantics;
|
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.
|
/// 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
|
/// 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,
|
super.onDragCompleted,
|
||||||
this.hapticFeedbackOnStart = true,
|
this.hapticFeedbackOnStart = true,
|
||||||
super.ignoringFeedbackSemantics,
|
super.ignoringFeedbackSemantics,
|
||||||
|
super.ignoringFeedbackPointer,
|
||||||
this.delay = kLongPressTimeout,
|
this.delay = kLongPressTimeout,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -542,6 +558,7 @@ class _DraggableState<T extends Object> extends State<Draggable<T>> {
|
|||||||
feedback: widget.feedback,
|
feedback: widget.feedback,
|
||||||
feedbackOffset: widget.feedbackOffset,
|
feedbackOffset: widget.feedbackOffset,
|
||||||
ignoringFeedbackSemantics: widget.ignoringFeedbackSemantics,
|
ignoringFeedbackSemantics: widget.ignoringFeedbackSemantics,
|
||||||
|
ignoringFeedbackPointer: widget.ignoringFeedbackPointer,
|
||||||
onDragUpdate: (DragUpdateDetails details) {
|
onDragUpdate: (DragUpdateDetails details) {
|
||||||
if (mounted && widget.onDragUpdate != null) {
|
if (mounted && widget.onDragUpdate != null) {
|
||||||
widget.onDragUpdate!(details);
|
widget.onDragUpdate!(details);
|
||||||
@ -796,8 +813,10 @@ class _DragAvatar<T extends Object> extends Drag {
|
|||||||
this.onDragUpdate,
|
this.onDragUpdate,
|
||||||
this.onDragEnd,
|
this.onDragEnd,
|
||||||
required this.ignoringFeedbackSemantics,
|
required this.ignoringFeedbackSemantics,
|
||||||
|
required this.ignoringFeedbackPointer,
|
||||||
}) : assert(overlayState != null),
|
}) : assert(overlayState != null),
|
||||||
assert(ignoringFeedbackSemantics != null),
|
assert(ignoringFeedbackSemantics != null),
|
||||||
|
assert(ignoringFeedbackPointer != null),
|
||||||
assert(dragStartPoint != null),
|
assert(dragStartPoint != null),
|
||||||
assert(feedbackOffset != null),
|
assert(feedbackOffset != null),
|
||||||
_position = initialPosition {
|
_position = initialPosition {
|
||||||
@ -815,6 +834,7 @@ class _DragAvatar<T extends Object> extends Drag {
|
|||||||
final _OnDragEnd? onDragEnd;
|
final _OnDragEnd? onDragEnd;
|
||||||
final OverlayState overlayState;
|
final OverlayState overlayState;
|
||||||
final bool ignoringFeedbackSemantics;
|
final bool ignoringFeedbackSemantics;
|
||||||
|
final bool ignoringFeedbackPointer;
|
||||||
|
|
||||||
_DragTargetState<Object>? _activeTarget;
|
_DragTargetState<Object>? _activeTarget;
|
||||||
final List<_DragTargetState<Object>> _enteredTargets = <_DragTargetState<Object>>[];
|
final List<_DragTargetState<Object>> _enteredTargets = <_DragTargetState<Object>>[];
|
||||||
@ -937,6 +957,7 @@ class _DragAvatar<T extends Object> extends Drag {
|
|||||||
left: _lastOffset!.dx - overlayTopLeft.dx,
|
left: _lastOffset!.dx - overlayTopLeft.dx,
|
||||||
top: _lastOffset!.dy - overlayTopLeft.dy,
|
top: _lastOffset!.dy - overlayTopLeft.dy,
|
||||||
child: IgnorePointer(
|
child: IgnorePointer(
|
||||||
|
ignoring: ignoringFeedbackPointer,
|
||||||
ignoringSemantics: ignoringFeedbackSemantics,
|
ignoringSemantics: ignoringFeedbackSemantics,
|
||||||
child: feedback,
|
child: feedback,
|
||||||
),
|
),
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/semantics.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
@ -3074,6 +3074,96 @@ void main() {
|
|||||||
expect(tester.widget<Listener>(find.byType(Listener).first).behavior, hitTestBehavior);
|
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 {
|
testWidgets('configurable DragTarget hit test behavior', (WidgetTester tester) async {
|
||||||
const HitTestBehavior hitTestBehavior = HitTestBehavior.deferToChild;
|
const HitTestBehavior hitTestBehavior = HitTestBehavior.deferToChild;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user