diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart index 151498ef33..94905ecf7c 100644 --- a/packages/flutter/lib/src/widgets/drag_target.dart +++ b/packages/flutter/lib/src/widgets/drag_target.dart @@ -267,6 +267,7 @@ class LongPressDraggable extends Draggable { VoidCallback onDragStarted, DraggableCanceledCallback onDraggableCanceled, VoidCallback onDragCompleted, + this.hapticFeedbackOnStart = true, bool ignoringFeedbackSemantics = true, }) : super( key: key, @@ -284,12 +285,15 @@ class LongPressDraggable extends Draggable { ignoringFeedbackSemantics: ignoringFeedbackSemantics, ); + /// Whether haptic feedback should be triggered on drag start. + final bool hapticFeedbackOnStart; + @override DelayedMultiDragGestureRecognizer createRecognizer(GestureMultiDragStartCallback onStart) { return new DelayedMultiDragGestureRecognizer() ..onStart = (Offset position) { final Drag result = onStart(position); - if (result != null) + if (result != null && hapticFeedbackOnStart) HapticFeedback.vibrate(); return result; }; diff --git a/packages/flutter/test/widgets/draggable_test.dart b/packages/flutter/test/widgets/draggable_test.dart index 084f49ff0e..4e2345fbd1 100644 --- a/packages/flutter/test/widgets/draggable_test.dart +++ b/packages/flutter/test/widgets/draggable_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/semantics.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; import 'package:flutter/gestures.dart'; @@ -1635,6 +1636,14 @@ void main() { expect(onDragStartedCalled, isTrue); }); + testWidgets('long-press draggable calls Haptic Feedback onStart', (WidgetTester tester) async { + await _testLongPressDraggableHapticFeedback(tester: tester, hapticFeedbackOnStart: true, expectedHapticFeedbackCount: 1); + }); + + testWidgets('long-press draggable can disable Haptic Feedback', (WidgetTester tester) async { + await _testLongPressDraggableHapticFeedback(tester: tester, hapticFeedbackOnStart: false, expectedHapticFeedbackCount: 0); + }); + testWidgets('Drag feedback with child anchor positions correctly', (WidgetTester tester) async { await _testChildAnchorFeedbackPosition(tester: tester); }); @@ -1793,6 +1802,48 @@ void main() { } +Future _testLongPressDraggableHapticFeedback({WidgetTester tester, bool hapticFeedbackOnStart, int expectedHapticFeedbackCount}) async { + bool onDragStartedCalled = false; + + int hapticFeedbackCalls = 0; + SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async { + if (methodCall.method == 'HapticFeedback.vibrate') { + hapticFeedbackCalls++; + } + }); + + await tester.pumpWidget(new MaterialApp( + home: new LongPressDraggable( + data: 1, + child: const Text('Source'), + feedback: const Text('Dragging'), + hapticFeedbackOnStart: hapticFeedbackOnStart, + onDragStarted: () { + onDragStartedCalled = true; + }, + ), + )); + + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsNothing); + expect(onDragStartedCalled, isFalse); + + final Offset firstLocation = tester.getCenter(find.text('Source')); + await tester.startGesture(firstLocation, pointer: 7); + await tester.pump(); + + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsNothing); + expect(onDragStartedCalled, isFalse); + + await tester.pump(kLongPressTimeout); + + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsOneWidget); + expect(onDragStartedCalled, isTrue); + expect(hapticFeedbackCalls, expectedHapticFeedbackCount); +} + Future _testChildAnchorFeedbackPosition({WidgetTester tester, double top = 0.0, double left = 0.0}) async { final List accepted = []; int dragStartedCount = 0;