diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart index 380d0330dc..712ae454db 100644 --- a/packages/flutter/lib/src/widgets/drag_target.dart +++ b/packages/flutter/lib/src/widgets/drag_target.dart @@ -10,6 +10,7 @@ import 'package:flutter/services.dart'; import 'basic.dart'; import 'binding.dart'; import 'framework.dart'; +import 'media_query.dart'; import 'overlay.dart'; /// Signature for determining whether the given data will be accepted by a [DragTarget]. @@ -500,6 +501,12 @@ class _DraggableState extends State> { super.dispose(); } + @override + void didChangeDependencies() { + _recognizer!.gestureSettings = MediaQuery.maybeOf(context)?.gestureSettings; + super.didChangeDependencies(); + } + // This gesture recognizer has an unusual lifetime. We want to support the use // case of removing the Draggable from the tree in the middle of a drag. That // means we need to keep this recognizer alive after this state object has diff --git a/packages/flutter/test/gestures/gesture_config_regression_test.dart b/packages/flutter/test/gestures/gesture_config_regression_test.dart index c21ade7824..c0c04a2907 100644 --- a/packages/flutter/test/gestures/gesture_config_regression_test.dart +++ b/packages/flutter/test/gestures/gesture_config_regression_test.dart @@ -13,16 +13,16 @@ class TestResult { bool dragUpdate = false; } -class MyHomePage extends StatefulWidget { - const MyHomePage({Key? key, required this.testResult}) : super(key: key); +class NestedScrollableCase extends StatefulWidget { + const NestedScrollableCase({Key? key, required this.testResult}) : super(key: key); final TestResult testResult; @override - State createState() => _MyHomePageState(); + State createState() => _NestedScrollableCaseState(); } -class _MyHomePageState extends State { +class _NestedScrollableCaseState extends State { @override Widget build(BuildContext context) { @@ -57,6 +57,50 @@ class _MyHomePageState extends State { } } +class NestedDragableCase extends StatefulWidget { + const NestedDragableCase({Key? key, required this.testResult}) : super(key: key); + + final TestResult testResult; + + @override + State createState() => _NestedDragableCaseState(); +} + +class _NestedDragableCaseState extends State { + + @override + Widget build(BuildContext context) { + return Scaffold( + body: CustomScrollView( + slivers: [ + SliverFixedExtentList( + itemExtent: 50.0, + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + return Container( + alignment: Alignment.center, + child: Draggable( + key: ValueKey(index), + feedback: const Text('Dragging'), + child: Text('List Item $index'), + onDragStarted: () { + widget.testResult.dragStarted = true; + }, + onDragUpdate: (DragUpdateDetails details){ + widget.testResult.dragUpdate = true; + }, + onDragEnd: (_) {}, + ), + ); + }, + ), + ), + ], + ), + ); + } +} + void main() { testWidgets('Scroll Views get the same ScrollConfiguration as GestureDetectors', (WidgetTester tester) async { tester.binding.window.viewConfigurationTestValue = const ui.ViewConfiguration( @@ -66,7 +110,30 @@ void main() { await tester.pumpWidget(MaterialApp( title: 'Scroll Bug', - home: MyHomePage(testResult: result), + home: NestedScrollableCase(testResult: result), + )); + + // By dragging the scroll view more than the configured touch slop above but less than + // the framework default value, we demonstrate that this causes gesture detectors + // that do not receive the same gesture settings to fire at different times than would + // be expected. + final Offset start = tester.getCenter(find.byKey(const ValueKey(1))); + await tester.timedDragFrom(start, const Offset(0, 5), const Duration(milliseconds: 50)); + await tester.pumpAndSettle(); + + expect(result.dragStarted, true); + expect(result.dragUpdate, true); + }); + + testWidgets('Scroll Views get the same ScrollConfiguration as Draggables', (WidgetTester tester) async { + tester.binding.window.viewConfigurationTestValue = const ui.ViewConfiguration( + gestureSettings: ui.GestureSettings(physicalTouchSlop: 4), + ); + final TestResult result = TestResult(); + + await tester.pumpWidget(MaterialApp( + title: 'Scroll Bug', + home: NestedDragableCase(testResult: result), )); // By dragging the scroll view more than the configured touch slop above but less than