diff --git a/packages/flutter/lib/src/material/range_slider.dart b/packages/flutter/lib/src/material/range_slider.dart index 5947a6aae050..48cf5ad4b6bf 100644 --- a/packages/flutter/lib/src/material/range_slider.dart +++ b/packages/flutter/lib/src/material/range_slider.dart @@ -704,6 +704,7 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget { textDirection: Directionality.of(context), semanticFormatterCallback: semanticFormatterCallback, platform: Theme.of(context).platform, + gestureSettings: MediaQuery.of(context).gestureSettings, ); } @@ -724,7 +725,8 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget { ..onChangeEnd = onChangeEnd ..textDirection = Directionality.of(context) ..semanticFormatterCallback = semanticFormatterCallback - ..platform = Theme.of(context).platform; + ..platform = Theme.of(context).platform + ..gestureSettings = MediaQuery.of(context).gestureSettings; } } @@ -744,6 +746,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix required this.onChangeEnd, required _RangeSliderState state, required TextDirection textDirection, + required DeviceGestureSettings gestureSettings, }) : assert(values != null), assert(values.start >= 0.0 && values.start <= 1.0), assert(values.end >= 0.0 && values.end <= 1.0), @@ -768,12 +771,14 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix ..onStart = _handleDragStart ..onUpdate = _handleDragUpdate ..onEnd = _handleDragEnd - ..onCancel = _handleDragCancel; + ..onCancel = _handleDragCancel + ..gestureSettings = gestureSettings; _tap = TapGestureRecognizer() ..team = team ..onTapDown = _handleTapDown ..onTapUp = _handleTapUp - ..onTapCancel = _handleTapCancel; + ..onTapCancel = _handleTapCancel + ..gestureSettings = gestureSettings; _overlayAnimation = CurvedAnimation( parent: _state.overlayController, curve: Curves.fastOutSlowIn, @@ -882,6 +887,12 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix markNeedsSemanticsUpdate(); } + DeviceGestureSettings? get gestureSettings => _drag.gestureSettings; + set gestureSettings(DeviceGestureSettings? gestureSettings) { + _drag.gestureSettings = gestureSettings; + _tap.gestureSettings = gestureSettings; + } + SemanticFormatterCallback? _semanticFormatterCallback; SemanticFormatterCallback? get semanticFormatterCallback => _semanticFormatterCallback; set semanticFormatterCallback(SemanticFormatterCallback? value) { diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index 44a9dff231b4..224873568bed 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/src/physics/utils.dart' show nearEqual; @@ -12,6 +12,113 @@ import 'package:flutter_test/flutter_test.dart'; import '../rendering/mock_canvas.dart'; void main() { + // Regression test for https://github.com/flutter/flutter/issues/105833 + testWidgets('Drag gesture uses provided gesture settings', (WidgetTester tester) async { + RangeValues values = const RangeValues(0.1, 0.5); + bool dragStarted = false; + final Key sliderKey = UniqueKey(); + + await tester.pumpWidget( + MaterialApp( + home: Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Material( + child: Center( + child: GestureDetector( + behavior: HitTestBehavior.deferToChild, + onHorizontalDragStart: (DragStartDetails details) { + dragStarted = true; + }, + child: MediaQuery( + data: MediaQuery.of(context).copyWith(gestureSettings: const DeviceGestureSettings(touchSlop: 20)), + child: RangeSlider( + key: sliderKey, + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, + ), + ), + ), + ), + ); + }, + ), + ), + ), + ); + + TestGesture drag = await tester.startGesture(tester.getCenter(find.byKey(sliderKey))); + await tester.pump(kPressTimeout); + + // Less than configured touch slop, more than default touch slop + await drag.moveBy(const Offset(19.0, 0)); + await tester.pump(); + + expect(values, const RangeValues(0.1, 0.5)); + expect(dragStarted, true); + + dragStarted = false; + + await drag.up(); + await tester.pumpAndSettle(); + + drag = await tester.startGesture(tester.getCenter(find.byKey(sliderKey))); + await tester.pump(kPressTimeout); + + bool sliderEnd = false; + + await tester.pumpWidget( + MaterialApp( + home: Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Material( + child: Center( + child: GestureDetector( + behavior: HitTestBehavior.deferToChild, + onHorizontalDragStart: (DragStartDetails details) { + dragStarted = true; + }, + child: MediaQuery( + data: MediaQuery.of(context).copyWith(gestureSettings: const DeviceGestureSettings(touchSlop: 10)), + child: RangeSlider( + key: sliderKey, + values: values, + onChanged: (RangeValues newValues) { + setState(() { + values = newValues; + }); + }, + onChangeEnd: (RangeValues newValues) { + sliderEnd = true; + }, + ), + ), + ), + ), + ); + }, + ), + ), + ), + ); + + // More than touch slop. + await drag.moveBy(const Offset(12.0, 0)); + + await drag.up(); + await tester.pumpAndSettle(); + + expect(sliderEnd, true); + expect(dragStarted, false); + }); + testWidgets('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7);