Skip to content

Commit 450401d

Browse files
authored
[Range slider] Tap on active range, the thumb closest to the mouse cursor should move to the cursor position. (flutter#173725)
Fix: flutter#172923 Internal issue: b/434778923 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1 parent 38eae2b commit 450401d

File tree

2 files changed

+31
-28
lines changed

2 files changed

+31
-28
lines changed

packages/flutter/lib/src/material/range_slider.dart

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -599,10 +599,13 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
599599
return RangeValues(_unlerp(values.start), _unlerp(values.end));
600600
}
601601

602-
// Finds closest thumb. If the thumbs are close to each other, no thumb is
603-
// immediately selected while the drag displacement is zero. If the first
604-
// non-zero displacement is negative, then the left thumb is selected, and if its
605-
// positive, then the right thumb is selected.
602+
// Finds the closest thumb. If both thumbs are close to each other and within
603+
// the touch radius, neither is selected immediately while the drag
604+
// displacement is zero. The first non-zero displacement determines which
605+
// thumb is selected: a negative displacement selects the left thumb,
606+
// a positive one selects the right thumb.
607+
// If only one or zero thumbs are within the touch radius,
608+
// the closest one is selected.
606609
Thumb? _defaultRangeThumbSelector(
607610
TextDirection textDirection,
608611
RangeValues values,
@@ -632,11 +635,10 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
632635
return Thumb.end;
633636
}
634637
} else {
635-
// Snap position on the track if its in the inactive range.
636-
if (tapValue < values.start || inStartTouchTarget) {
638+
// Choose the closest thumb and snap position.
639+
if (tapValue * 2 < values.start + values.end) {
637640
return Thumb.start;
638-
}
639-
if (tapValue > values.end || inEndTouchTarget) {
641+
} else {
640642
return Thumb.end;
641643
}
642644
}

packages/flutter/test/material/range_slider_test.dart

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ void main() {
125125
});
126126

127127
testWidgets('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async {
128-
RangeValues values = const RangeValues(0.3, 0.7);
128+
RangeValues values = const RangeValues(0.3, 0.8);
129129

130130
await tester.pumpWidget(
131131
MaterialApp(
@@ -151,13 +151,13 @@ void main() {
151151
),
152152
);
153153

154-
// No thumbs get select when tapping between the thumbs outside the touch
154+
// The closest thumb is selected when tapping between the thumbs outside the touch
155155
// boundaries
156-
expect(values, equals(const RangeValues(0.3, 0.7)));
156+
expect(values, equals(const RangeValues(0.3, 0.8)));
157157
// taps at 0.5
158158
await tester.tap(find.byType(RangeSlider));
159159
await tester.pump();
160-
expect(values, equals(const RangeValues(0.3, 0.7)));
160+
expect(values, equals(const RangeValues(0.5, 0.8)));
161161

162162
// Get the bounds of the track by finding the slider edges and translating
163163
// inwards by the overlay radius.
@@ -168,7 +168,7 @@ void main() {
168168
final Offset leftTarget = topLeft + (bottomRight - topLeft) * 0.1;
169169
await tester.tapAt(leftTarget);
170170
expect(values.start, moreOrLessEquals(0.1, epsilon: 0.01));
171-
expect(values.end, equals(0.7));
171+
expect(values.end, equals(0.8));
172172

173173
// The end thumb is selected when tapping the right inactive track.
174174
await tester.pump();
@@ -179,7 +179,7 @@ void main() {
179179
});
180180

181181
testWidgets('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async {
182-
RangeValues values = const RangeValues(0.3, 0.7);
182+
RangeValues values = const RangeValues(0.3, 1.0);
183183

184184
await tester.pumpWidget(
185185
MaterialApp(
@@ -205,13 +205,13 @@ void main() {
205205
),
206206
);
207207

208-
// No thumbs get select when tapping between the thumbs outside the touch
208+
// The closest thumb is selected when tapping between the thumbs outside the touch
209209
// boundaries
210-
expect(values, equals(const RangeValues(0.3, 0.7)));
210+
expect(values, equals(const RangeValues(0.3, 1.0)));
211211
// taps at 0.5
212212
await tester.tap(find.byType(RangeSlider));
213213
await tester.pump();
214-
expect(values, equals(const RangeValues(0.3, 0.7)));
214+
expect(values, equals(const RangeValues(0.5, 1.0)));
215215

216216
// Get the bounds of the track by finding the slider edges and translating
217217
// inwards by the overlay radius.
@@ -221,7 +221,7 @@ void main() {
221221
// The end thumb is selected when tapping the left inactive track.
222222
final Offset leftTarget = topLeft + (bottomRight - topLeft) * 0.1;
223223
await tester.tapAt(leftTarget);
224-
expect(values.start, 0.3);
224+
expect(values.start, 0.5);
225225
expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01));
226226

227227
// The start thumb is selected when tapping the right inactive track.
@@ -233,7 +233,7 @@ void main() {
233233
});
234234

235235
testWidgets('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async {
236-
RangeValues values = const RangeValues(30, 70);
236+
RangeValues values = const RangeValues(30, 80);
237237

238238
await tester.pumpWidget(
239239
MaterialApp(
@@ -261,13 +261,13 @@ void main() {
261261
),
262262
);
263263

264-
// No thumbs get select when tapping between the thumbs outside the touch
264+
// The closest thumb is selected when tapping between the thumbs outside the touch
265265
// boundaries
266-
expect(values, equals(const RangeValues(30, 70)));
266+
expect(values, equals(const RangeValues(30, 80)));
267267
// taps at 0.5
268268
await tester.tap(find.byType(RangeSlider));
269269
await tester.pumpAndSettle();
270-
expect(values, equals(const RangeValues(30, 70)));
270+
expect(values, equals(const RangeValues(50, 80)));
271271

272272
// Get the bounds of the track by finding the slider edges and translating
273273
// inwards by the overlay radius.
@@ -279,7 +279,7 @@ void main() {
279279
await tester.tapAt(leftTarget);
280280
await tester.pumpAndSettle();
281281
expect(values.start.round(), equals(10));
282-
expect(values.end.round(), equals(70));
282+
expect(values.end.round(), equals(80));
283283

284284
// The end thumb is selected when tapping the right inactive track.
285285
await tester.pump();
@@ -291,7 +291,7 @@ void main() {
291291
});
292292

293293
testWidgets('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async {
294-
RangeValues values = const RangeValues(30, 70);
294+
RangeValues values = const RangeValues(30, 80);
295295

296296
await tester.pumpWidget(
297297
MaterialApp(
@@ -319,13 +319,13 @@ void main() {
319319
),
320320
);
321321

322-
// No thumbs get select when tapping between the thumbs outside the touch
322+
// The closest thumb is selected when tapping between the thumbs outside the touch
323323
// boundaries
324-
expect(values, equals(const RangeValues(30, 70)));
324+
expect(values, equals(const RangeValues(30, 80)));
325325
// taps at 0.5
326326
await tester.tap(find.byType(RangeSlider));
327327
await tester.pumpAndSettle();
328-
expect(values, equals(const RangeValues(30, 70)));
328+
expect(values, equals(const RangeValues(50, 80)));
329329

330330
// Get the bounds of the track by finding the slider edges and translating
331331
// inwards by the overlay radius.
@@ -336,7 +336,7 @@ void main() {
336336
final Offset leftTarget = topLeft + (bottomRight - topLeft) * 0.1;
337337
await tester.tapAt(leftTarget);
338338
await tester.pumpAndSettle();
339-
expect(values.start.round(), equals(30));
339+
expect(values.start.round(), equals(50));
340340
expect(values.end.round(), equals(90));
341341

342342
// The end thumb is selected when tapping the right inactive track.
@@ -744,6 +744,7 @@ void main() {
744744
final Offset rightTarget = topLeft + (bottomRight - topLeft) * 0.7;
745745
await tester.dragFrom(rightTarget, middle - rightTarget);
746746
expect(values.start, moreOrLessEquals(50, epsilon: 0.01));
747+
expect(values.end, moreOrLessEquals(50, epsilon: 0.01));
747748

748749
// Drag the start thumb apart.
749750
await tester.pumpAndSettle();

0 commit comments

Comments
 (0)