Unverified Commit 5d96d619 authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Add MaterialStateProperty `overlayColor` & `mouseCursor` and fix hovering on...

Add  MaterialStateProperty `overlayColor` & `mouseCursor` and fix hovering on thumbs behavior (#116894)
parent 07bc2452
......@@ -14,6 +14,7 @@ import 'package:flutter/widgets.dart';
import 'constants.dart';
import 'debug.dart';
import 'material_state.dart';
import 'slider_theme.dart';
import 'theme.dart';
......@@ -144,6 +145,8 @@ class RangeSlider extends StatefulWidget {
this.labels,
this.activeColor,
this.inactiveColor,
this.overlayColor,
this.mouseCursor,
this.semanticFormatterCallback,
}) : assert(values != null),
assert(min != null),
......@@ -322,6 +325,26 @@ class RangeSlider extends StatefulWidget {
/// appearance of various components of the slider.
final Color? inactiveColor;
/// The highlight color that's typically used to indicate that
/// the range slider thumb is hovered or dragged.
///
/// If this property is null, [RangeSlider] will use [activeColor] with
/// with an opacity of 0.12. If null, [SliderThemeData.overlayColor]
/// will be used, otherwise defaults to [ColorScheme.primary] with
/// an opacity of 0.12.
final MaterialStateProperty<Color?>? overlayColor;
/// The cursor for a mouse pointer when it enters or is hovering over the
/// widget.
///
/// If null, then the value of [SliderThemeData.mouseCursor] is used. If that
/// is also null, then [MaterialStateMouseCursor.clickable] is used.
///
/// See also:
///
/// * [MaterialStateMouseCursor], which can be used to create a [MouseCursor].
final MaterialStateProperty<MouseCursor?>? mouseCursor;
/// The callback used to create a semantic value from the slider's values.
///
/// Defaults to formatting values as a percentage.
......@@ -400,6 +423,16 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
PaintRangeValueIndicator? paintTopValueIndicator;
PaintRangeValueIndicator? paintBottomValueIndicator;
bool get _enabled => widget.onChanged != null;
bool _dragging = false;
bool _hovering = false;
void _handleHoverChanged(bool hovering) {
if (hovering != _hovering) {
setState(() { _hovering = hovering; });
}
}
@override
void initState() {
......@@ -415,7 +448,7 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
enableController = AnimationController(
duration: enableAnimationDuration,
vsync: this,
value: widget.onChanged != null ? 1.0 : 0.0,
value: _enabled ? 1.0 : 0.0,
);
startPositionController = AnimationController(
duration: Duration.zero,
......@@ -436,7 +469,7 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
return;
}
final bool wasEnabled = oldWidget.onChanged != null;
final bool isEnabled = widget.onChanged != null;
final bool isEnabled = _enabled;
if (wasEnabled != isEnabled) {
if (isEnabled) {
enableController.forward();
......@@ -462,7 +495,7 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
}
void _handleChanged(RangeValues values) {
assert(widget.onChanged != null);
assert(_enabled);
final RangeValues lerpValues = _lerpRangeValues(values);
if (lerpValues != widget.values) {
widget.onChanged!(lerpValues);
......@@ -471,11 +504,13 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
void _handleDragStart(RangeValues values) {
assert(widget.onChangeStart != null);
_dragging = true;
widget.onChangeStart!(_lerpRangeValues(values));
}
void _handleDragEnd(RangeValues values) {
assert(widget.onChangeEnd != null);
_dragging = false;
widget.onChangeEnd!(_lerpRangeValues(values));
}
......@@ -576,6 +611,12 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
const ShowValueIndicator defaultShowValueIndicator = ShowValueIndicator.onlyForDiscrete;
const double defaultMinThumbSeparation = 8;
final Set<MaterialState> states = <MaterialState>{
if (!_enabled) MaterialState.disabled,
if (_hovering) MaterialState.hovered,
if (_dragging) MaterialState.dragged,
};
// The value indicator's color is not the same as the thumb and active track
// (which can be defined by activeColor) if the
// RectangularSliderValueIndicatorShape is used. In all other cases, the
......@@ -588,6 +629,13 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
valueIndicatorColor = widget.activeColor ?? sliderTheme.valueIndicatorColor ?? theme.colorScheme.primary;
}
Color? effectiveOverlayColor() {
return widget.overlayColor?.resolve(states)
?? widget.activeColor?.withOpacity(0.12)
?? MaterialStateProperty.resolveAs<Color?>(sliderTheme.overlayColor, states)
?? theme.colorScheme.primary.withOpacity(0.12);
}
sliderTheme = sliderTheme.copyWith(
trackHeight: sliderTheme.trackHeight ?? defaultTrackHeight,
activeTrackColor: widget.activeColor ?? sliderTheme.activeTrackColor ?? theme.colorScheme.primary,
......@@ -601,7 +649,7 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
thumbColor: widget.activeColor ?? sliderTheme.thumbColor ?? theme.colorScheme.primary,
overlappingShapeStrokeColor: sliderTheme.overlappingShapeStrokeColor ?? theme.colorScheme.surface,
disabledThumbColor: sliderTheme.disabledThumbColor ?? Color.alphaBlend(theme.colorScheme.onSurface.withOpacity(.38), theme.colorScheme.surface),
overlayColor: widget.activeColor?.withOpacity(0.12) ?? sliderTheme.overlayColor ?? theme.colorScheme.primary.withOpacity(0.12),
overlayColor: effectiveOverlayColor(),
valueIndicatorColor: valueIndicatorColor,
rangeTrackShape: sliderTheme.rangeTrackShape ?? defaultTrackShape,
rangeTickMarkShape: sliderTheme.rangeTickMarkShape ?? defaultTickMarkShape,
......@@ -615,26 +663,36 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
minThumbSeparation: sliderTheme.minThumbSeparation ?? defaultMinThumbSeparation,
thumbSelector: sliderTheme.thumbSelector ?? _defaultRangeThumbSelector,
);
final MouseCursor effectiveMouseCursor = widget.mouseCursor?.resolve(states)
?? sliderTheme.mouseCursor?.resolve(states)
?? MaterialStateMouseCursor.clickable.resolve(states);
// This size is used as the max bounds for the painting of the value
// indicators. It must be kept in sync with the function with the same name
// in slider.dart.
Size screenSize() => MediaQuery.sizeOf(context);
return CompositedTransformTarget(
link: _layerLink,
child: _RangeSliderRenderObjectWidget(
values: _unlerpRangeValues(widget.values),
divisions: widget.divisions,
labels: widget.labels,
sliderTheme: sliderTheme,
textScaleFactor: MediaQuery.textScaleFactorOf(context),
screenSize: screenSize(),
onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null,
onChangeStart: widget.onChangeStart != null ? _handleDragStart : null,
onChangeEnd: widget.onChangeEnd != null ? _handleDragEnd : null,
state: this,
semanticFormatterCallback: widget.semanticFormatterCallback,
return FocusableActionDetector(
enabled: _enabled,
onShowHoverHighlight: _handleHoverChanged,
includeFocusSemantics: false,
mouseCursor: effectiveMouseCursor,
child: CompositedTransformTarget(
link: _layerLink,
child: _RangeSliderRenderObjectWidget(
values: _unlerpRangeValues(widget.values),
divisions: widget.divisions,
labels: widget.labels,
sliderTheme: sliderTheme,
textScaleFactor: MediaQuery.of(context).textScaleFactor,
screenSize: screenSize(),
onChanged: _enabled && (widget.max > widget.min) ? _handleChanged : null,
onChangeStart: widget.onChangeStart != null ? _handleDragStart : null,
onChangeEnd: widget.onChangeEnd != null ? _handleDragEnd : null,
state: this,
semanticFormatterCallback: widget.semanticFormatterCallback,
hovering: _hovering,
),
),
);
}
......@@ -673,6 +731,7 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget {
required this.onChangeEnd,
required this.state,
required this.semanticFormatterCallback,
required this.hovering,
});
final RangeValues values;
......@@ -686,6 +745,7 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget {
final ValueChanged<RangeValues>? onChangeEnd;
final SemanticFormatterCallback? semanticFormatterCallback;
final _RangeSliderState state;
final bool hovering;
@override
_RenderRangeSlider createRenderObject(BuildContext context) {
......@@ -704,6 +764,7 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget {
textDirection: Directionality.of(context),
semanticFormatterCallback: semanticFormatterCallback,
platform: Theme.of(context).platform,
hovering: hovering,
gestureSettings: MediaQuery.gestureSettingsOf(context),
);
}
......@@ -726,6 +787,7 @@ class _RangeSliderRenderObjectWidget extends LeafRenderObjectWidget {
..textDirection = Directionality.of(context)
..semanticFormatterCallback = semanticFormatterCallback
..platform = Theme.of(context).platform
..hovering = hovering
..gestureSettings = MediaQuery.gestureSettingsOf(context);
}
}
......@@ -746,6 +808,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
required this.onChangeEnd,
required _RangeSliderState state,
required TextDirection textDirection,
required bool hovering,
required DeviceGestureSettings gestureSettings,
}) : assert(values != null),
assert(values.start >= 0.0 && values.start <= 1.0),
......@@ -763,7 +826,8 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
_screenSize = screenSize,
_onChanged = onChanged,
_state = state,
_textDirection = textDirection {
_textDirection = textDirection,
_hovering = hovering {
_updateLabelPainters();
final GestureArenaTeam team = GestureArenaTeam();
_drag = HorizontalDragGestureRecognizer()
......@@ -842,6 +906,8 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
late RangeValues _newValues;
late Offset _startThumbCenter;
late Offset _endThumbCenter;
Rect? overlayStartRect;
Rect? overlayEndRect;
bool get isEnabled => onChanged != null;
......@@ -993,6 +1059,53 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
_updateLabelPainters();
}
/// True if this slider is being hovered over by a pointer.
bool get hovering => _hovering;
bool _hovering;
set hovering(bool value) {
assert(value != null);
if (value == _hovering) {
return;
}
_hovering = value;
_updateForHover(_hovering);
}
/// True if the slider is interactive and the start thumb is being
/// hovered over by a pointer.
bool _hoveringStartThumb = false;
bool get hoveringStartThumb => _hoveringStartThumb;
set hoveringStartThumb(bool value) {
assert(value != null);
if (value == _hoveringStartThumb) {
return;
}
_hoveringStartThumb = value;
_updateForHover(_hovering);
}
/// True if the slider is interactive and the end thumb is being
/// hovered over by a pointer.
bool _hoveringEndThumb = false;
bool get hoveringEndThumb => _hoveringEndThumb;
set hoveringEndThumb(bool value) {
assert(value != null);
if (value == _hoveringEndThumb) {
return;
}
_hoveringEndThumb = value;
_updateForHover(_hovering);
}
void _updateForHover(bool hovered) {
// Only show overlay when pointer is hovering the thumb.
if (hovered && (hoveringStartThumb || hoveringEndThumb)) {
_state.overlayController.forward();
} else {
_state.overlayController.reverse();
}
}
bool get showValueIndicator {
switch (_sliderTheme.showValueIndicator!) {
case ShowValueIndicator.onlyForDiscrete:
......@@ -1253,6 +1366,14 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
_drag.addPointer(event);
_tap.addPointer(event);
}
if (isEnabled) {
if (overlayStartRect != null) {
hoveringStartThumb = overlayStartRect!.contains(event.localPosition);
}
if (overlayEndRect != null) {
hoveringEndThumb = overlayEndRect!.contains(event.localPosition);
}
}
}
@override
......@@ -1307,6 +1428,11 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
);
_startThumbCenter = Offset(trackRect.left + startVisualPosition * trackRect.width, trackRect.center.dy);
_endThumbCenter = Offset(trackRect.left + endVisualPosition * trackRect.width, trackRect.center.dy);
if (isEnabled) {
final Size overlaySize = sliderTheme.overlayShape!.getPreferredSize(isEnabled, false);
overlayStartRect = Rect.fromCircle(center: _startThumbCenter, radius: overlaySize.width / 2.0);
overlayEndRect = Rect.fromCircle(center: _endThumbCenter, radius: overlaySize.width / 2.0);
}
_sliderTheme.rangeTrackShape!.paint(
context,
......@@ -1326,7 +1452,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
final Size resolvedscreenSize = screenSize.isEmpty ? size : screenSize;
if (!_overlayAnimation.isDismissed) {
if (startThumbSelected) {
if (startThumbSelected || hoveringStartThumb) {
_sliderTheme.overlayShape!.paint(
context,
_startThumbCenter,
......@@ -1342,7 +1468,7 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
sizeWithOverflow: resolvedscreenSize,
);
}
if (endThumbSelected) {
if (endThumbSelected || hoveringEndThumb) {
_sliderTheme.overlayShape!.paint(
context,
_endThumbCenter,
......
......@@ -2177,4 +2177,367 @@ void main() {
expect(nearEqual(activeTrackRect.left, (800.0 - 24.0 - 24.0) * (5 / 15) + 24.0, 0.01), true);
expect(nearEqual(activeTrackRect.right, (800.0 - 24.0 - 24.0) * (8 / 15) + 24.0, 0.01), true);
});
testWidgets('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async {
const RangeValues values = RangeValues(50, 70);
// Test default cursor.
await tester.pumpWidget(
MaterialApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: MouseRegion(
cursor: SystemMouseCursors.forbidden,
child: RangeSlider(
values: values,
max: 100.0,
onChanged: (RangeValues values) {},
),
),
),
),
),
),
);
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
await gesture.addPointer(location: tester.getCenter(find.byType(RangeSlider)));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click);
// Test custom cursor.
await tester.pumpWidget(
MaterialApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: Center(
child: MouseRegion(
cursor: SystemMouseCursors.forbidden,
child: RangeSlider(
values: values,
max: 100.0,
mouseCursor: const MaterialStatePropertyAll<MouseCursor?>(SystemMouseCursors.text),
onChanged: (RangeValues values) {},
),
),
),
),
),
),
);
await tester.pump();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text);
});
testWidgets('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async {
RangeValues values = const RangeValues(50, 70);
const MouseCursor disabledCursor = SystemMouseCursors.basic;
const MouseCursor hoveredCursor = SystemMouseCursors.grab;
const MouseCursor draggedCursor = SystemMouseCursors.move;
Widget buildFrame({ required bool enabled }) {
return MaterialApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Center(
child: MouseRegion(
cursor: SystemMouseCursors.forbidden,
child: RangeSlider(
mouseCursor: MaterialStateProperty.resolveWith<MouseCursor?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabledCursor;
}
if (states.contains(MaterialState.dragged)) {
return draggedCursor;
}
if (states.contains(MaterialState.hovered)) {
return hoveredCursor;
}
return SystemMouseCursors.none;
},
),
values: values,
max: 100.0,
onChanged: enabled
? (RangeValues newValues) {
setState(() {
values = newValues;
});
}
: null,
onChangeStart: enabled ? (RangeValues newValues) {} : null,
onChangeEnd: enabled ? (RangeValues newValues) {} : null,
),
),
);
},
),
),
),
);
}
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1);
await gesture.addPointer(location: Offset.zero);
await tester.pumpWidget(buildFrame(enabled: false));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), disabledCursor);
await tester.pumpWidget(buildFrame(enabled: true));
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.none);
await gesture.moveTo(tester.getCenter(find.byType(RangeSlider))); // start hover
await tester.pumpAndSettle();
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), hoveredCursor);
await tester.timedDrag(
find.byType(RangeSlider),
const Offset(20.0, 0.0),
const Duration(milliseconds: 100),
);
expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), draggedCursor);
});
testWidgets('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
RangeValues values = const RangeValues(50, 70);
final ThemeData theme = ThemeData();
Widget buildApp({bool enabled = true}) {
return MaterialApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: RangeSlider(
values: values,
max: 100.0,
onChanged: enabled
? (RangeValues newValues) {
setState(() {
values = newValues;
});
}
: null,
),
),
);
},
),
),
);
}
await tester.pumpWidget(buildApp());
// RangeSlider does not have overlay when enabled and not hovered.
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
);
// Start hovering.
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer();
await gesture.moveTo(tester.getCenter(find.byType(RangeSlider)));
// RangeSlider has overlay when enabled and hovered.
await tester.pumpWidget(buildApp());
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
);
// RangeSlider does not have an overlay when disabled and hovered.
await tester.pumpWidget(buildApp(enabled: false));
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
);
});
testWidgets('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
RangeValues values = const RangeValues(50, 70);
final ThemeData theme = ThemeData();
Widget buildApp({bool enabled = true}) {
return MaterialApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: RangeSlider(
values: values,
max: 100.0,
onChanged: enabled
? (RangeValues newValues) {
setState(() {
values = newValues;
});
}
: null,
),
),
);
},
),
),
);
}
await tester.pumpWidget(buildApp());
// RangeSlider does not have overlay when enabled and not dragged.
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
isNot(paints..circle(color: theme.colorScheme.primary.withOpacity(0.12))),
);
// Start dragging.
final TestGesture drag = await tester.startGesture(tester.getCenter(find.byType(RangeSlider)));
await tester.pump(kPressTimeout);
// Less than configured touch slop, more than default touch slop
await drag.moveBy(const Offset(19.0, 0));
await tester.pump();
// RangeSlider has overlay when enabled and dragged.
expect(
Material.of(tester.element(find.byType(RangeSlider))),
paints..circle(color: theme.colorScheme.primary.withOpacity(0.12)),
);
});
testWidgets('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async {
tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
RangeValues values = const RangeValues(50, 70);
const Color hoverColor = Color(0xffff0000);
const Color draggedColor = Color(0xff0000ff);
Widget buildApp({bool enabled = true}) {
return MaterialApp(
home: Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: RangeSlider(
values: values,
max: 100.0,
overlayColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return hoverColor;
}
if (states.contains(MaterialState.dragged)) {
return draggedColor;
}
return null;
}),
onChanged: enabled
? (RangeValues newValues) {
setState(() {
values = newValues;
});
}
: null,
onChangeStart: enabled ? (RangeValues newValues) {} : null,
onChangeEnd: enabled ? (RangeValues newValues) {} : null,
),
),
);
},
),
),
);
}
await tester.pumpWidget(buildApp());
// RangeSlider does not have overlay when enabled and not hovered.
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
isNot(paints..circle(color: hoverColor)),
);
// Hover on the range slider but outside the thumb.
final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
await gesture.addPointer();
await gesture.moveTo(tester.getTopLeft(find.byType(RangeSlider)));
await tester.pumpWidget(buildApp());
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
isNot(paints..circle(color: hoverColor)),
);
// Hover on the thumb.
await gesture.moveTo(tester.getCenter(find.byType(RangeSlider)));
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
paints..circle(color: hoverColor),
);
// Hover on the slider but outside the thumb.
await gesture.moveTo(tester.getBottomRight(find.byType(RangeSlider)));
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
isNot(paints..circle(color: hoverColor)),
);
// Reset range slider values.
values = const RangeValues(50, 70);
// RangeSlider does not have overlay when enabled and not dragged.
await tester.pumpWidget(buildApp());
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
isNot(paints..circle(color: draggedColor)),
);
// Start dragging.
final TestGesture drag = await tester.startGesture(tester.getCenter(find.byType(RangeSlider)));
await tester.pump(kPressTimeout);
// Less than configured touch slop, more than default touch slop.
await drag.moveBy(const Offset(19.0, 0));
await tester.pump();
// RangeSlider has overlay when enabled and dragged.
expect(
Material.of(tester.element(find.byType(RangeSlider))),
paints..circle(color: draggedColor),
);
// Stop dragging.
await drag.up();
await tester.pumpAndSettle();
expect(
Material.of(tester.element(find.byType(RangeSlider))),
isNot(paints..circle(color: draggedColor)),
);
});
}
......@@ -308,10 +308,6 @@ void main() {
).createShader(bounds),
child: const Placeholder(),
),
RangeSlider(
values: const RangeValues(0.3, 0.7),
onChanged: (RangeValues newValues) {},
),
CompositedTransformFollower(
link: LayerLink(),
),
......@@ -339,9 +335,6 @@ void main() {
renderObject = tester.firstRenderObject(find.byType(ShaderMask));
expect(renderObject.debugLayer?.debugCreator, isNotNull);
renderObject = tester.firstRenderObject(find.byType(RangeSlider));
expect(renderObject.debugLayer?.debugCreator, isNotNull);
renderObject = tester.firstRenderObject(find.byType(CompositedTransformFollower));
expect(renderObject.debugLayer?.debugCreator, isNotNull);
});
......
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