Skip to content

Commit f733e3a

Browse files
authored
Fix multiple calls to Slider's onChanged. (#143680)
Fixes #143524
1 parent ff9b1a5 commit f733e3a

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,11 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
612612

613613
bool _dragging = false;
614614

615+
// For discrete sliders, _handleChanged might receive the same value
616+
// multiple times. To avoid calling widget.onChanged repeatedly, the
617+
// value from _handleChanged is temporarily saved here.
618+
double? _currentChangedValue;
619+
615620
FocusNode? _focusNode;
616621
FocusNode get focusNode => widget.focusNode ?? _focusNode!;
617622

@@ -664,8 +669,11 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
664669
void _handleChanged(double value) {
665670
assert(widget.onChanged != null);
666671
final double lerpValue = _lerp(value);
667-
if (lerpValue != widget.value) {
668-
widget.onChanged!(lerpValue);
672+
if (_currentChangedValue != lerpValue) {
673+
_currentChangedValue = lerpValue;
674+
if (_currentChangedValue != widget.value) {
675+
widget.onChanged!(_currentChangedValue!);
676+
}
669677
}
670678
}
671679

@@ -676,6 +684,7 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
676684

677685
void _handleDragEnd(double value) {
678686
_dragging = false;
687+
_currentChangedValue = null;
679688
widget.onChangeEnd?.call(_lerp(value));
680689
}
681690

packages/flutter/test/material/slider_test.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4253,4 +4253,32 @@ void main() {
42534253
);
42544254
});
42554255
});
4256+
4257+
// This is a regression test for https://github.com/flutter/flutter/issues/143524.
4258+
testWidgets('Discrete Slider.onChanged is called only once', (WidgetTester tester) async {
4259+
int onChangeCallbackCount = 0;
4260+
await tester.pumpWidget(
4261+
MaterialApp(
4262+
home: Scaffold(
4263+
body: Center(
4264+
child: Slider(
4265+
max: 5,
4266+
divisions: 5,
4267+
value: 0,
4268+
onChanged: (double newValue) {
4269+
onChangeCallbackCount++;
4270+
},
4271+
),
4272+
),
4273+
),
4274+
),
4275+
);
4276+
4277+
final TestGesture gesture = await tester.startGesture(tester.getTopLeft(find.byType(Slider)));
4278+
await tester.pump(kLongPressTimeout);
4279+
await gesture.moveBy(const Offset(160.0, 0.0));
4280+
await gesture.moveBy(const Offset(1.0, 0.0));
4281+
await gesture.moveBy(const Offset(1.0, 0.0));
4282+
expect(onChangeCallbackCount, 1);
4283+
});
42564284
}

0 commit comments

Comments
 (0)