Unverified Commit 5530c106 authored by hgraceb's avatar hgraceb Committed by GitHub

Optimize the display of the Overlay on the Slider (#139021)

## Description

Automatic focus request on Slider value change prevents Overlay from correctly handling hover events.

Fixes #139281

### Before

![slider3](https://github.com/flutter/flutter/assets/38378650/815e12a4-ccaf-4b99-8480-6cbdc97a91bd)

### After

![slider4](https://github.com/flutter/flutter/assets/38378650/473eca22-0308-4964-8368-b0c158ae30eb)
parent 3f1f0aa5
......@@ -666,7 +666,6 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
final double lerpValue = _lerp(value);
if (lerpValue != widget.value) {
widget.onChanged!(lerpValue);
_focusNode?.requestFocus();
}
}
......@@ -1376,8 +1375,8 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
if (hovered && hoveringThumb) {
_state.overlayController.forward();
} else {
// Only remove overlay when Slider is unfocused.
if (!hasFocus) {
// Only remove overlay when Slider is inactive and unfocused.
if (!_active && !hasFocus) {
_state.overlayController.reverse();
}
}
......
......@@ -3396,6 +3396,99 @@ void main() {
expect(dragStarted, false);
});
// Regression test for https://github.com/flutter/flutter/issues/139281
testWidgetsWithLeakTracking('Slider does not request focus when the value is changed', (WidgetTester tester) async {
double value = 0.5;
await tester.pumpWidget(MaterialApp(
home: Material(
child: Center(
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
return Slider(
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
}
);
}),
),
),
));
// Initially, the slider does not have focus whe enabled and not tapped.
await tester.pumpAndSettle();
expect(value, equals(0.5));
// Get FocusNode from the state of the slider to include auto-generated FocusNode.
// ignore: avoid_dynamic_calls, invalid_assignment
final FocusNode focusNode = (tester.firstState(find.byType(Slider)) as dynamic).focusNode;
// The slider does not have focus.
expect(focusNode.hasFocus, false);
final Offset sliderCenter = tester.getCenter(find.byType(Slider));
final Offset tapLocation = Offset(sliderCenter.dx + 50, sliderCenter.dy);
// Tap on the slider to change the value.
final TestGesture gesture = await tester.createGesture();
await gesture.addPointer();
await gesture.down(tapLocation);
await gesture.up();
await tester.pumpAndSettle();
expect(value, isNot(equals(0.5)));
// The slider does not have have focus after the value is changed.
expect(focusNode.hasFocus, false);
});
// Regression test for https://github.com/flutter/flutter/issues/139281
testWidgetsWithLeakTracking('Overlay remains when Slider thumb is interacted', (WidgetTester tester) async {
double value = 0.5;
const Color overlayColor = Color(0xffff0000);
await tester.pumpWidget(MaterialApp(
home: Material(
child: Center(
child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
return Slider(
value: value,
overlayColor: const MaterialStatePropertyAll<Color?>(overlayColor),
onChanged: (double newValue) {
setState(() {
value = newValue;
});
}
);
}),
),
),
));
// Slider does not have overlay when enabled and not tapped.
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(Slider))),
isNot(paints..circle(color: overlayColor)),
);
final Offset sliderCenter = tester.getCenter(find.byType(Slider));
// Tap and hold down on the thumb to keep it active.
final TestGesture gesture = await tester.createGesture();
await gesture.addPointer();
await gesture.down(sliderCenter);
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(Slider))),
paints..circle(color: overlayColor),
);
// Hover on the slider but outside the thumb.
await gesture.moveTo(tester.getTopLeft(find.byType(Slider)));
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(Slider))),
paints..circle(color: overlayColor),
);
// Tap up on the slider.
await gesture.up();
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(Slider))),
isNot(paints..circle(color: overlayColor)),
);
});
testWidgetsWithLeakTracking('Overlay appear only when hovered on the thumb on desktop', (WidgetTester tester) async {
double value = 0.5;
const Color overlayColor = Color(0xffff0000);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment