@@ -1748,7 +1748,7 @@ void main() {
17481748 paints..circle (color: Colors .orange[500 ]),
17491749 );
17501750
1751- // Check that the overlay does not show when focused and disabled.
1751+ // Check that the overlay does not show when unfocused and disabled.
17521752 await tester.pumpWidget (buildApp (enabled: false ));
17531753 await tester.pumpAndSettle ();
17541754 expect (focusNode.hasPrimaryFocus, isFalse);
@@ -1990,10 +1990,10 @@ void main() {
19901990 await drag.up ();
19911991 await tester.pumpAndSettle ();
19921992
1993- // Slider does not have an overlay when stopped dragging.
1993+ // Slider still has overlay when stopped dragging.
19941994 expect (
19951995 Material .of (tester.element (find.byType (Slider ))),
1996- isNot ( paints..circle (color: Colors .lime[500 ]) ),
1996+ paints..circle (color: Colors .lime[500 ]),
19971997 );
19981998 });
19991999
@@ -3177,4 +3177,208 @@ void main() {
31773177 expect (sliderEnd, true );
31783178 expect (dragStarted, false );
31793179 });
3180+
3181+ testWidgets ('Overlay appear only when hovered on the thumb on desktop' , (WidgetTester tester) async {
3182+ double value = 0.5 ;
3183+ const Color overlayColor = Color (0xffff0000 );
3184+
3185+ Widget buildApp ({bool enabled = true }) {
3186+ return MaterialApp (
3187+ home: Material (
3188+ child: Center (
3189+ child: StatefulBuilder (builder: (BuildContext context, StateSetter setState) {
3190+ return Slider (
3191+ value: value,
3192+ overlayColor: const MaterialStatePropertyAll <Color ?>(overlayColor),
3193+ onChanged: enabled
3194+ ? (double newValue) {
3195+ setState (() {
3196+ value = newValue;
3197+ });
3198+ }
3199+ : null ,
3200+ );
3201+ }),
3202+ ),
3203+ ),
3204+ );
3205+ }
3206+ await tester.pumpWidget (buildApp ());
3207+
3208+ // Slider does not have overlay when enabled and not hovered.
3209+ await tester.pumpAndSettle ();
3210+ expect (
3211+ Material .of (tester.element (find.byType (Slider ))),
3212+ isNot (paints..circle (color: overlayColor)),
3213+ );
3214+
3215+ // Hover on the slider but outside the thumb.
3216+ final TestGesture gesture = await tester.createGesture (kind: PointerDeviceKind .mouse);
3217+ await gesture.addPointer ();
3218+ await gesture.moveTo (tester.getTopLeft (find.byType (Slider )));
3219+
3220+ await tester.pumpWidget (buildApp ());
3221+ await tester.pumpAndSettle ();
3222+ expect (
3223+ Material .of (tester.element (find.byType (Slider ))),
3224+ isNot (paints..circle (color: overlayColor)),
3225+ );
3226+
3227+ // Hover on the thumb.
3228+ await gesture.moveTo (tester.getCenter (find.byType (Slider )));
3229+ await tester.pumpAndSettle ();
3230+ expect (
3231+ Material .of (tester.element (find.byType (Slider ))),
3232+ paints..circle (color: overlayColor),
3233+ );
3234+
3235+ // Hover on the slider but outside the thumb.
3236+ await gesture.moveTo (tester.getBottomRight (find.byType (Slider )));
3237+ await tester.pumpAndSettle ();
3238+ expect (
3239+ Material .of (tester.element (find.byType (Slider ))),
3240+ isNot (paints..circle (color: overlayColor)),
3241+ );
3242+ }, variant: TargetPlatformVariant .desktop ());
3243+
3244+ testWidgets ('Overlay remains when Slider is in focus on desktop' , (WidgetTester tester) async {
3245+ double value = 0.5 ;
3246+ const Color overlayColor = Color (0xffff0000 );
3247+ final FocusNode focusNode = FocusNode ();
3248+
3249+ Widget buildApp ({bool enabled = true }) {
3250+ return MaterialApp (
3251+ home: Material (
3252+ child: Center (
3253+ child: StatefulBuilder (builder: (BuildContext context, StateSetter setState) {
3254+ return Slider (
3255+ value: value,
3256+ focusNode: focusNode,
3257+ overlayColor: const MaterialStatePropertyAll <Color ?>(overlayColor),
3258+ onChanged: enabled
3259+ ? (double newValue) {
3260+ setState (() {
3261+ value = newValue;
3262+ });
3263+ }
3264+ : null ,
3265+ );
3266+ }),
3267+ ),
3268+ ),
3269+ );
3270+ }
3271+ await tester.pumpWidget (buildApp ());
3272+
3273+ // Slider does not have overlay when enabled and not tapped.
3274+ await tester.pumpAndSettle ();
3275+ expect (focusNode.hasFocus, false );
3276+ expect (
3277+ Material .of (tester.element (find.byType (Slider ))),
3278+ isNot (paints..circle (color: overlayColor)),
3279+ );
3280+
3281+ final Offset sliderCenter = tester.getCenter (find.byType (Slider ));
3282+ Offset tapLocation = Offset (sliderCenter.dx + 50 , sliderCenter.dy);
3283+
3284+ // Tap somewhere to bring overlay.
3285+ final TestGesture gesture = await tester.createGesture (kind: PointerDeviceKind .mouse);
3286+ await gesture.addPointer ();
3287+ await gesture.down (tapLocation);
3288+ await gesture.up ();
3289+ focusNode.requestFocus ();
3290+ await tester.pumpAndSettle ();
3291+ expect (focusNode.hasFocus, true );
3292+ expect (
3293+ Material .of (tester.element (find.byType (Slider ))),
3294+ paints..circle (color: overlayColor),
3295+ );
3296+
3297+ tapLocation = Offset (sliderCenter.dx - 50 , sliderCenter.dy);
3298+ await gesture.down (tapLocation);
3299+ await gesture.up ();
3300+ await tester.pumpAndSettle ();
3301+ expect (focusNode.hasFocus, true );
3302+ expect (
3303+ Material .of (tester.element (find.byType (Slider ))),
3304+ paints..circle (color: overlayColor),
3305+ );
3306+
3307+ focusNode.unfocus ();
3308+ await tester.pumpAndSettle ();
3309+ expect (focusNode.hasFocus, false );
3310+ expect (
3311+ Material .of (tester.element (find.byType (Slider ))),
3312+ isNot (paints..circle (color: overlayColor)),
3313+ );
3314+ }, variant: TargetPlatformVariant .desktop ());
3315+
3316+ testWidgets ('Value indicator remains when Slider is in focus on desktop' , (WidgetTester tester) async {
3317+ double value = 0.5 ;
3318+ final FocusNode focusNode = FocusNode ();
3319+
3320+ Widget buildApp ({bool enabled = true }) {
3321+ return MaterialApp (
3322+ theme: ThemeData (
3323+ sliderTheme: const SliderThemeData (
3324+ showValueIndicator: ShowValueIndicator .always,
3325+ ),
3326+ ),
3327+ home: Material (
3328+ child: Center (
3329+ child: StatefulBuilder (builder: (BuildContext context, StateSetter setState) {
3330+ return Slider (
3331+ value: value,
3332+ focusNode: focusNode,
3333+ divisions: 5 ,
3334+ label: value.toStringAsFixed (1 ),
3335+ onChanged: enabled
3336+ ? (double newValue) {
3337+ setState (() {
3338+ value = newValue;
3339+ });
3340+ }
3341+ : null ,
3342+ );
3343+ }),
3344+ ),
3345+ ),
3346+ );
3347+ }
3348+ await tester.pumpWidget (buildApp ());
3349+
3350+ // Slider does not show value indicator without focus.
3351+ await tester.pumpAndSettle ();
3352+ expect (focusNode.hasFocus, false );
3353+ RenderBox valueIndicatorBox = tester.renderObject (find.byType (Overlay ));
3354+ expect (
3355+ valueIndicatorBox,
3356+ isNot (paints..path (color: const Color (0xff000000 ))..paragraph ()),
3357+ );
3358+
3359+ final Offset sliderCenter = tester.getCenter (find.byType (Slider ));
3360+ final Offset tapLocation = Offset (sliderCenter.dx + 50 , sliderCenter.dy);
3361+
3362+ // Tap somewhere to bring value indicator.
3363+ final TestGesture gesture = await tester.createGesture (kind: PointerDeviceKind .mouse);
3364+ await gesture.addPointer ();
3365+ await gesture.down (tapLocation);
3366+ await gesture.up ();
3367+ focusNode.requestFocus ();
3368+ await tester.pumpAndSettle ();
3369+ expect (focusNode.hasFocus, true );
3370+ valueIndicatorBox = tester.renderObject (find.byType (Overlay ));
3371+ expect (
3372+ valueIndicatorBox,
3373+ paints..path (color: const Color (0xff000000 ))..paragraph (),
3374+ );
3375+
3376+ focusNode.unfocus ();
3377+ await tester.pumpAndSettle ();
3378+ expect (focusNode.hasFocus, false );
3379+ expect (
3380+ valueIndicatorBox,
3381+ isNot (paints..path (color: const Color (0xff000000 ))..paragraph ()),
3382+ );
3383+ }, variant: TargetPlatformVariant .desktop ());
31803384}
0 commit comments