Fix multiple calls to Slider's onChanged. (#143680)

Fixes #143524
This commit is contained in:
yim 2024-03-09 15:50:23 +08:00 committed by GitHub
parent ff9b1a5c22
commit f733e3a441
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 2 deletions

View file

@ -612,6 +612,11 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
bool _dragging = false;
// For discrete sliders, _handleChanged might receive the same value
// multiple times. To avoid calling widget.onChanged repeatedly, the
// value from _handleChanged is temporarily saved here.
double? _currentChangedValue;
FocusNode? _focusNode;
FocusNode get focusNode => widget.focusNode ?? _focusNode!;
@ -664,8 +669,11 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
void _handleChanged(double value) {
assert(widget.onChanged != null);
final double lerpValue = _lerp(value);
if (lerpValue != widget.value) {
widget.onChanged!(lerpValue);
if (_currentChangedValue != lerpValue) {
_currentChangedValue = lerpValue;
if (_currentChangedValue != widget.value) {
widget.onChanged!(_currentChangedValue!);
}
}
}
@ -676,6 +684,7 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
void _handleDragEnd(double value) {
_dragging = false;
_currentChangedValue = null;
widget.onChangeEnd?.call(_lerp(value));
}

View file

@ -4253,4 +4253,32 @@ void main() {
);
});
});
// This is a regression test for https://github.com/flutter/flutter/issues/143524.
testWidgets('Discrete Slider.onChanged is called only once', (WidgetTester tester) async {
int onChangeCallbackCount = 0;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: Center(
child: Slider(
max: 5,
divisions: 5,
value: 0,
onChanged: (double newValue) {
onChangeCallbackCount++;
},
),
),
),
),
);
final TestGesture gesture = await tester.startGesture(tester.getTopLeft(find.byType(Slider)));
await tester.pump(kLongPressTimeout);
await gesture.moveBy(const Offset(160.0, 0.0));
await gesture.moveBy(const Offset(1.0, 0.0));
await gesture.moveBy(const Offset(1.0, 0.0));
expect(onChangeCallbackCount, 1);
});
}