Skip to content

Commit d72daf6

Browse files
authored
CupertinoSlider: Add clickable cursor for web (#99557)
1 parent 7d8a556 commit d72daf6

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

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

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
import 'dart:math' as math;
66
import 'dart:ui' show lerpDouble;
77

8-
import 'package:flutter/foundation.dart' show clampDouble;
8+
import 'package:flutter/foundation.dart';
99
import 'package:flutter/gestures.dart';
1010
import 'package:flutter/rendering.dart';
11+
import 'package:flutter/services.dart';
1112
import 'package:flutter/widgets.dart';
1213

1314
import 'colors.dart';
@@ -294,6 +295,7 @@ class _CupertinoSliderRenderObjectWidget extends LeafRenderObjectWidget {
294295
onChangeEnd: onChangeEnd,
295296
vsync: vsync,
296297
textDirection: Directionality.of(context),
298+
cursor: kIsWeb ? SystemMouseCursors.click : MouseCursor.defer,
297299
);
298300
}
299301

@@ -322,7 +324,7 @@ const Duration _kDiscreteTransitionDuration = Duration(milliseconds: 500);
322324

323325
const double _kAdjustmentUnit = 0.1; // Matches iOS implementation of material slider.
324326

325-
class _RenderCupertinoSlider extends RenderConstrainedBox {
327+
class _RenderCupertinoSlider extends RenderConstrainedBox implements MouseTrackerAnnotation {
326328
_RenderCupertinoSlider({
327329
required double value,
328330
int? divisions,
@@ -334,8 +336,11 @@ class _RenderCupertinoSlider extends RenderConstrainedBox {
334336
this.onChangeEnd,
335337
required TickerProvider vsync,
336338
required TextDirection textDirection,
339+
MouseCursor cursor = MouseCursor.defer,
337340
}) : assert(value != null && value >= 0.0 && value <= 1.0),
338341
assert(textDirection != null),
342+
assert(cursor != null),
343+
_cursor = cursor,
339344
_value = value,
340345
_divisions = divisions,
341346
_activeColor = activeColor,
@@ -584,4 +589,27 @@ class _RenderCupertinoSlider extends RenderConstrainedBox {
584589
onChanged!(clampDouble(value - _semanticActionUnit, 0.0, 1.0));
585590
}
586591
}
592+
593+
@override
594+
MouseCursor get cursor => _cursor;
595+
MouseCursor _cursor;
596+
set cursor(MouseCursor value) {
597+
if (_cursor != value) {
598+
_cursor = value;
599+
// A repaint is needed in order to trigger a device update of
600+
// [MouseTracker] so that this new value can be found.
601+
markNeedsPaint();
602+
}
603+
}
604+
605+
@override
606+
PointerEnterEventListener? onEnter;
607+
608+
PointerHoverEventListener? onHover;
609+
610+
@override
611+
PointerExitEventListener? onExit;
612+
613+
@override
614+
bool get validForMouseTracker => false;
587615
}

packages/flutter/test/cupertino/slider_test.dart

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// found in the LICENSE file.
44

55
import 'package:flutter/cupertino.dart';
6+
import 'package:flutter/foundation.dart';
7+
import 'package:flutter/gestures.dart';
68
import 'package:flutter/material.dart';
79
import 'package:flutter/rendering.dart';
810
import 'package:flutter/scheduler.dart';
@@ -613,4 +615,46 @@ void main() {
613615
..rrect(color: CupertinoColors.activeOrange.color),
614616
);
615617
});
618+
619+
testWidgets('Hovering over Cupertino slider thumb updates cursor to clickable on Web', (WidgetTester tester) async {
620+
final Key sliderKey = UniqueKey();
621+
double value = 0.0;
622+
623+
await tester.pumpWidget(
624+
CupertinoApp(
625+
home: Directionality(
626+
textDirection: TextDirection.ltr,
627+
child: StatefulBuilder(
628+
builder: (BuildContext context, StateSetter setState) {
629+
return Material(
630+
child: Center(
631+
child: CupertinoSlider(
632+
key: sliderKey,
633+
value: value,
634+
onChanged: (double newValue) {
635+
setState(() { value = newValue; });
636+
},
637+
),
638+
),
639+
);
640+
},
641+
),
642+
),
643+
),
644+
);
645+
646+
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
647+
await gesture.addPointer(location: const Offset(10, 10));
648+
await tester.pumpAndSettle();
649+
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic);
650+
651+
final Offset topLeft = tester.getTopLeft(find.byKey(sliderKey));
652+
await gesture.moveTo(topLeft + const Offset(15, 0));
653+
addTearDown(gesture.removePointer);
654+
await tester.pumpAndSettle();
655+
expect(
656+
RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1),
657+
kIsWeb ? SystemMouseCursors.click : SystemMouseCursors.basic,
658+
);
659+
});
616660
}

0 commit comments

Comments
 (0)