Add ability to customize the default Slider
padding (#156143)
Fixes [Ability to change Sliders padding](https://github.com/flutter/flutter/issues/40098) Add ability to override default padding so the Slider can fit better in a layout. ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatefulWidget { const MyApp({super.key}); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { double _sliderValue = 0.5; @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( sliderTheme: const SliderThemeData( padding: EdgeInsets.symmetric(vertical: 4.0), thumbColor: Colors.red, inactiveTrackColor: Colors.amber, ), ), home: Scaffold( body: Directionality( textDirection: TextDirection.ltr, child: Center( child: Card( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4.0)), ), color: Theme.of(context).colorScheme.surfaceContainerHighest, margin: const EdgeInsets.symmetric(horizontal: 16.0), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ const Placeholder(fallbackHeight: 100.0), Slider( value: _sliderValue, onChanged: (double value) { setState(() { _sliderValue = value; }); }, ), const Placeholder(fallbackHeight: 100.0), ], ), ), ), ), ), ), ); } } ``` </details> ### Before (Cannot adjust default `Slider` padding to fill the horizontal space in a `Column` and reduce the padded height) <img width="717" alt="Screenshot 2024-10-03 at 15 45 18" src="https://github.com/user-attachments/assets/e9d9a4d1-3087-45b4-8607-b94411e2bd23"> ### After Can adjust default `Slider` padding via `SliderTheme`) <img width="717" alt="Screenshot 2024-10-03 at 15 46 25" src="https://github.com/user-attachments/assets/cd455881-6d52-46cb-8ac6-cc33f50a13ff">
This commit is contained in:
parent
ec50578982
commit
40c22749f5
@ -196,6 +196,7 @@ class Slider extends StatefulWidget {
|
|||||||
this.focusNode,
|
this.focusNode,
|
||||||
this.autofocus = false,
|
this.autofocus = false,
|
||||||
this.allowedInteraction,
|
this.allowedInteraction,
|
||||||
|
this.padding,
|
||||||
}) : _sliderType = _SliderType.material,
|
}) : _sliderType = _SliderType.material,
|
||||||
assert(min <= max),
|
assert(min <= max),
|
||||||
assert(value >= min && value <= max,
|
assert(value >= min && value <= max,
|
||||||
@ -238,6 +239,7 @@ class Slider extends StatefulWidget {
|
|||||||
this.autofocus = false,
|
this.autofocus = false,
|
||||||
this.allowedInteraction,
|
this.allowedInteraction,
|
||||||
}) : _sliderType = _SliderType.adaptive,
|
}) : _sliderType = _SliderType.adaptive,
|
||||||
|
padding = null,
|
||||||
assert(min <= max),
|
assert(min <= max),
|
||||||
assert(value >= min && value <= max,
|
assert(value >= min && value <= max,
|
||||||
'Value $value is not between minimum $min and maximum $max'),
|
'Value $value is not between minimum $min and maximum $max'),
|
||||||
@ -550,6 +552,14 @@ class Slider extends StatefulWidget {
|
|||||||
/// Defaults to [SliderInteraction.tapAndSlide].
|
/// Defaults to [SliderInteraction.tapAndSlide].
|
||||||
final SliderInteraction? allowedInteraction;
|
final SliderInteraction? allowedInteraction;
|
||||||
|
|
||||||
|
/// Determines the padding around the [Slider].
|
||||||
|
///
|
||||||
|
/// If specified, this padding overrides the default vertical padding of
|
||||||
|
/// the [Slider], defaults to the height of the overlay shape, and the
|
||||||
|
/// horizontal padding, defaults to the width of the thumb shape or
|
||||||
|
/// overlay shape, whichever is larger.
|
||||||
|
final EdgeInsetsGeometry? padding;
|
||||||
|
|
||||||
final _SliderType _sliderType ;
|
final _SliderType _sliderType ;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -853,6 +863,7 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
|||||||
valueIndicatorShape: valueIndicatorShape,
|
valueIndicatorShape: valueIndicatorShape,
|
||||||
showValueIndicator: sliderTheme.showValueIndicator ?? defaultShowValueIndicator,
|
showValueIndicator: sliderTheme.showValueIndicator ?? defaultShowValueIndicator,
|
||||||
valueIndicatorTextStyle: valueIndicatorTextStyle,
|
valueIndicatorTextStyle: valueIndicatorTextStyle,
|
||||||
|
padding: widget.padding ?? sliderTheme.padding,
|
||||||
);
|
);
|
||||||
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor?>(widget.mouseCursor, states)
|
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor?>(widget.mouseCursor, states)
|
||||||
?? sliderTheme.mouseCursor?.resolve(states)
|
?? sliderTheme.mouseCursor?.resolve(states)
|
||||||
@ -899,6 +910,36 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
|||||||
: MediaQuery.textScalerOf(context);
|
: MediaQuery.textScalerOf(context);
|
||||||
final double effectiveTextScale = textScaler.scale(fontSizeToScale) / fontSizeToScale;
|
final double effectiveTextScale = textScaler.scale(fontSizeToScale) / fontSizeToScale;
|
||||||
|
|
||||||
|
Widget result = CompositedTransformTarget(
|
||||||
|
link: _layerLink,
|
||||||
|
child: _SliderRenderObjectWidget(
|
||||||
|
key: _renderObjectKey,
|
||||||
|
value: _convert(widget.value),
|
||||||
|
secondaryTrackValue: (widget.secondaryTrackValue != null) ? _convert(widget.secondaryTrackValue!) : null,
|
||||||
|
divisions: widget.divisions,
|
||||||
|
label: widget.label,
|
||||||
|
sliderTheme: sliderTheme,
|
||||||
|
textScaleFactor: effectiveTextScale,
|
||||||
|
screenSize: screenSize(),
|
||||||
|
onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null,
|
||||||
|
onChangeStart: _handleDragStart,
|
||||||
|
onChangeEnd: _handleDragEnd,
|
||||||
|
state: this,
|
||||||
|
semanticFormatterCallback: widget.semanticFormatterCallback,
|
||||||
|
hasFocus: _focused,
|
||||||
|
hovering: _hovering,
|
||||||
|
allowedInteraction: effectiveAllowedInteraction,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final EdgeInsetsGeometry? padding = widget.padding ?? sliderTheme.padding;
|
||||||
|
if (padding != null) {
|
||||||
|
result = Padding(
|
||||||
|
padding: padding,
|
||||||
|
child: result,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Semantics(
|
return Semantics(
|
||||||
container: true,
|
container: true,
|
||||||
slider: true,
|
slider: true,
|
||||||
@ -912,27 +953,7 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
|||||||
onShowFocusHighlight: _handleFocusHighlightChanged,
|
onShowFocusHighlight: _handleFocusHighlightChanged,
|
||||||
onShowHoverHighlight: _handleHoverChanged,
|
onShowHoverHighlight: _handleHoverChanged,
|
||||||
mouseCursor: effectiveMouseCursor,
|
mouseCursor: effectiveMouseCursor,
|
||||||
child: CompositedTransformTarget(
|
child: result,
|
||||||
link: _layerLink,
|
|
||||||
child: _SliderRenderObjectWidget(
|
|
||||||
key: _renderObjectKey,
|
|
||||||
value: _convert(widget.value),
|
|
||||||
secondaryTrackValue: (widget.secondaryTrackValue != null) ? _convert(widget.secondaryTrackValue!) : null,
|
|
||||||
divisions: widget.divisions,
|
|
||||||
label: widget.label,
|
|
||||||
sliderTheme: sliderTheme,
|
|
||||||
textScaleFactor: effectiveTextScale,
|
|
||||||
screenSize: screenSize(),
|
|
||||||
onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null,
|
|
||||||
onChangeStart: _handleDragStart,
|
|
||||||
onChangeEnd: _handleDragEnd,
|
|
||||||
state: this,
|
|
||||||
semanticFormatterCallback: widget.semanticFormatterCallback,
|
|
||||||
hasFocus: _focused,
|
|
||||||
hovering: _hovering,
|
|
||||||
allowedInteraction: effectiveAllowedInteraction,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1145,8 +1166,13 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
|
|||||||
// centered on the track.
|
// centered on the track.
|
||||||
double get _maxSliderPartWidth => _sliderPartSizes.map((Size size) => size.width).reduce(math.max);
|
double get _maxSliderPartWidth => _sliderPartSizes.map((Size size) => size.width).reduce(math.max);
|
||||||
double get _maxSliderPartHeight => _sliderPartSizes.map((Size size) => size.height).reduce(math.max);
|
double get _maxSliderPartHeight => _sliderPartSizes.map((Size size) => size.height).reduce(math.max);
|
||||||
|
double get _thumbSizeHeight => _sliderTheme.thumbShape!.getPreferredSize(isInteractive, isDiscrete).height;
|
||||||
|
double get _overlayHeight => _sliderTheme.overlayShape!.getPreferredSize(isInteractive, isDiscrete).height;
|
||||||
List<Size> get _sliderPartSizes => <Size>[
|
List<Size> get _sliderPartSizes => <Size>[
|
||||||
_sliderTheme.overlayShape!.getPreferredSize(isInteractive, isDiscrete),
|
Size(
|
||||||
|
_sliderTheme.overlayShape!.getPreferredSize(isInteractive, isDiscrete).width,
|
||||||
|
_sliderTheme.padding != null ? _thumbSizeHeight : _overlayHeight
|
||||||
|
),
|
||||||
_sliderTheme.thumbShape!.getPreferredSize(isInteractive, isDiscrete),
|
_sliderTheme.thumbShape!.getPreferredSize(isInteractive, isDiscrete),
|
||||||
_sliderTheme.tickMarkShape!.getPreferredSize(isEnabled: isInteractive, sliderTheme: sliderTheme),
|
_sliderTheme.tickMarkShape!.getPreferredSize(isEnabled: isInteractive, sliderTheme: sliderTheme),
|
||||||
];
|
];
|
||||||
|
@ -296,6 +296,7 @@ class SliderThemeData with Diagnosticable {
|
|||||||
this.thumbSelector,
|
this.thumbSelector,
|
||||||
this.mouseCursor,
|
this.mouseCursor,
|
||||||
this.allowedInteraction,
|
this.allowedInteraction,
|
||||||
|
this.padding,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Generates a SliderThemeData from three main colors.
|
/// Generates a SliderThemeData from three main colors.
|
||||||
@ -588,6 +589,14 @@ class SliderThemeData with Diagnosticable {
|
|||||||
/// If specified, overrides the default value of [Slider.allowedInteraction].
|
/// If specified, overrides the default value of [Slider.allowedInteraction].
|
||||||
final SliderInteraction? allowedInteraction;
|
final SliderInteraction? allowedInteraction;
|
||||||
|
|
||||||
|
/// Determines the padding around the [Slider].
|
||||||
|
///
|
||||||
|
/// If specified, this padding overrides the default vertical padding of
|
||||||
|
/// the [Slider], defaults to the height of the overlay shape, and the
|
||||||
|
/// horizontal padding, defaults to the width of the thumb shape or
|
||||||
|
/// overlay shape, whichever is larger.
|
||||||
|
final EdgeInsetsGeometry? padding;
|
||||||
|
|
||||||
/// Creates a copy of this object but with the given fields replaced with the
|
/// Creates a copy of this object but with the given fields replaced with the
|
||||||
/// new values.
|
/// new values.
|
||||||
SliderThemeData copyWith({
|
SliderThemeData copyWith({
|
||||||
@ -623,6 +632,7 @@ class SliderThemeData with Diagnosticable {
|
|||||||
RangeThumbSelector? thumbSelector,
|
RangeThumbSelector? thumbSelector,
|
||||||
MaterialStateProperty<MouseCursor?>? mouseCursor,
|
MaterialStateProperty<MouseCursor?>? mouseCursor,
|
||||||
SliderInteraction? allowedInteraction,
|
SliderInteraction? allowedInteraction,
|
||||||
|
EdgeInsetsGeometry? padding,
|
||||||
}) {
|
}) {
|
||||||
return SliderThemeData(
|
return SliderThemeData(
|
||||||
trackHeight: trackHeight ?? this.trackHeight,
|
trackHeight: trackHeight ?? this.trackHeight,
|
||||||
@ -657,6 +667,7 @@ class SliderThemeData with Diagnosticable {
|
|||||||
thumbSelector: thumbSelector ?? this.thumbSelector,
|
thumbSelector: thumbSelector ?? this.thumbSelector,
|
||||||
mouseCursor: mouseCursor ?? this.mouseCursor,
|
mouseCursor: mouseCursor ?? this.mouseCursor,
|
||||||
allowedInteraction: allowedInteraction ?? this.allowedInteraction,
|
allowedInteraction: allowedInteraction ?? this.allowedInteraction,
|
||||||
|
padding: padding ?? this.padding,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,6 +711,7 @@ class SliderThemeData with Diagnosticable {
|
|||||||
thumbSelector: t < 0.5 ? a.thumbSelector : b.thumbSelector,
|
thumbSelector: t < 0.5 ? a.thumbSelector : b.thumbSelector,
|
||||||
mouseCursor: t < 0.5 ? a.mouseCursor : b.mouseCursor,
|
mouseCursor: t < 0.5 ? a.mouseCursor : b.mouseCursor,
|
||||||
allowedInteraction: t < 0.5 ? a.allowedInteraction : b.allowedInteraction,
|
allowedInteraction: t < 0.5 ? a.allowedInteraction : b.allowedInteraction,
|
||||||
|
padding: EdgeInsetsGeometry.lerp(a.padding, b.padding, t),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,6 +749,7 @@ class SliderThemeData with Diagnosticable {
|
|||||||
thumbSelector,
|
thumbSelector,
|
||||||
mouseCursor,
|
mouseCursor,
|
||||||
allowedInteraction,
|
allowedInteraction,
|
||||||
|
padding,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -780,7 +793,8 @@ class SliderThemeData with Diagnosticable {
|
|||||||
&& other.minThumbSeparation == minThumbSeparation
|
&& other.minThumbSeparation == minThumbSeparation
|
||||||
&& other.thumbSelector == thumbSelector
|
&& other.thumbSelector == thumbSelector
|
||||||
&& other.mouseCursor == mouseCursor
|
&& other.mouseCursor == mouseCursor
|
||||||
&& other.allowedInteraction == allowedInteraction;
|
&& other.allowedInteraction == allowedInteraction
|
||||||
|
&& other.padding == padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -819,6 +833,7 @@ class SliderThemeData with Diagnosticable {
|
|||||||
properties.add(DiagnosticsProperty<RangeThumbSelector>('thumbSelector', thumbSelector, defaultValue: defaultData.thumbSelector));
|
properties.add(DiagnosticsProperty<RangeThumbSelector>('thumbSelector', thumbSelector, defaultValue: defaultData.thumbSelector));
|
||||||
properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, defaultValue: defaultData.mouseCursor));
|
properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, defaultValue: defaultData.mouseCursor));
|
||||||
properties.add(EnumProperty<SliderInteraction>('allowedInteraction', allowedInteraction, defaultValue: defaultData.allowedInteraction));
|
properties.add(EnumProperty<SliderInteraction>('allowedInteraction', allowedInteraction, defaultValue: defaultData.allowedInteraction));
|
||||||
|
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: defaultData.padding));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1535,9 +1550,9 @@ mixin BaseSliderTrackShape {
|
|||||||
assert(overlayWidth >= 0);
|
assert(overlayWidth >= 0);
|
||||||
assert(trackHeight >= 0);
|
assert(trackHeight >= 0);
|
||||||
|
|
||||||
final double trackLeft = offset.dx + math.max(overlayWidth / 2, thumbWidth / 2);
|
final double trackLeft = offset.dx + (sliderTheme.padding == null ? math.max(overlayWidth / 2, thumbWidth / 2) : 0);
|
||||||
final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
|
final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
|
||||||
final double trackRight = trackLeft + parentBox.size.width - math.max(thumbWidth, overlayWidth);
|
final double trackRight = trackLeft + parentBox.size.width - (sliderTheme.padding == null ? math.max(thumbWidth, overlayWidth) : 0);
|
||||||
final double trackBottom = trackTop + trackHeight;
|
final double trackBottom = trackTop + trackHeight;
|
||||||
// If the parentBox's size less than slider's size the trackRight will be less than trackLeft, so switch them.
|
// If the parentBox's size less than slider's size the trackRight will be less than trackLeft, so switch them.
|
||||||
return Rect.fromLTRB(math.min(trackLeft, trackRight), trackTop, math.max(trackLeft, trackRight), trackBottom);
|
return Rect.fromLTRB(math.min(trackLeft, trackRight), trackTop, math.max(trackLeft, trackRight), trackBottom);
|
||||||
|
@ -4598,4 +4598,93 @@ void main() {
|
|||||||
paints..path(color: const Color(0xff000000))..paragraph(),
|
paints..path(color: const Color(0xff000000))..paragraph(),
|
||||||
);
|
);
|
||||||
}, variant: TargetPlatformVariant.desktop());
|
}, variant: TargetPlatformVariant.desktop());
|
||||||
|
|
||||||
|
testWidgets('Slider.padding can override the default Slider padding', (WidgetTester tester) async {
|
||||||
|
Widget buildSlider({ EdgeInsetsGeometry? padding }) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Slider(
|
||||||
|
padding: padding,
|
||||||
|
value: 0.5,
|
||||||
|
onChanged: (double value) {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderBox sliderRenderBox() {
|
||||||
|
return tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderSlider') as RenderBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Slider height and tracks spacing with zero padding.
|
||||||
|
await tester.pumpWidget(buildSlider(padding: EdgeInsets.zero));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// The height equals to the default thumb height.
|
||||||
|
expect(sliderRenderBox().size, const Size(800, 20));
|
||||||
|
expect(
|
||||||
|
find.byType(Slider),
|
||||||
|
paints
|
||||||
|
// Inactive track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(398.0, 8.0, 800.0, 12.0, const Radius.circular(2.0)),
|
||||||
|
)
|
||||||
|
// Active track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(0.0, 7.0, 402.0, 13.0, const Radius.circular(3.0)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test Slider height and tracks spacing with directional padding.
|
||||||
|
const double startPadding = 100;
|
||||||
|
const double endPadding = 20;
|
||||||
|
await tester.pumpWidget(buildSlider(
|
||||||
|
padding: const EdgeInsetsDirectional.only(
|
||||||
|
start: startPadding,
|
||||||
|
end: endPadding,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(sliderRenderBox().size, const Size(800 - startPadding - endPadding, 20));
|
||||||
|
expect(
|
||||||
|
find.byType(Slider),
|
||||||
|
paints
|
||||||
|
// Inactive track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(338.0, 8.0, 680.0, 12.0, const Radius.circular(2.0)),
|
||||||
|
)
|
||||||
|
// Active track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(0.0, 7.0, 342.0, 13.0, const Radius.circular(3.0)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Test Slider height and tracks spacing with top and bottom padding.
|
||||||
|
const double topPadding = 100;
|
||||||
|
const double bottomPadding = 20;
|
||||||
|
const double trackHeight = 20;
|
||||||
|
await tester.pumpWidget(buildSlider(padding: const EdgeInsetsDirectional.only(top: topPadding, bottom: bottomPadding)));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(tester.getSize(find.byType(Slider)), const Size(800, topPadding + trackHeight + bottomPadding));
|
||||||
|
expect(sliderRenderBox().size, const Size(800, 20));
|
||||||
|
expect(
|
||||||
|
find.byType(Slider),
|
||||||
|
paints
|
||||||
|
// Inactive track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(398.0, 8.0, 800.0, 12.0, const Radius.circular(2.0)),
|
||||||
|
)
|
||||||
|
// Active track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(0.0, 7.0, 402.0, 13.0, const Radius.circular(3.0)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -2551,6 +2551,95 @@ void main() {
|
|||||||
expect(const RoundedRectSliderTrackShape().isRounded, isTrue);
|
expect(const RoundedRectSliderTrackShape().isRounded, isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('SliderThemeData.padding can override the default Slider padding', (WidgetTester tester) async {
|
||||||
|
Widget buildSlider({ EdgeInsetsGeometry? padding }) {
|
||||||
|
return MaterialApp(
|
||||||
|
theme: ThemeData(sliderTheme: SliderThemeData(padding: padding)),
|
||||||
|
home: Material(
|
||||||
|
child: Center(
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Slider(
|
||||||
|
value: 0.5,
|
||||||
|
onChanged: (double value) {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderBox sliderRenderBox() {
|
||||||
|
return tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderSlider') as RenderBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Slider height and tracks spacing with zero padding.
|
||||||
|
await tester.pumpWidget(buildSlider(padding: EdgeInsets.zero));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// The height equals to the default thumb height.
|
||||||
|
expect(sliderRenderBox().size, const Size(800, 20));
|
||||||
|
expect(
|
||||||
|
find.byType(Slider),
|
||||||
|
paints
|
||||||
|
// Inactive track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(398.0, 8.0, 800.0, 12.0, const Radius.circular(2.0)),
|
||||||
|
)
|
||||||
|
// Active track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(0.0, 7.0, 402.0, 13.0, const Radius.circular(3.0)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test Slider height and tracks spacing with directional padding.
|
||||||
|
const double startPadding = 100;
|
||||||
|
const double endPadding = 20;
|
||||||
|
await tester.pumpWidget(buildSlider(
|
||||||
|
padding: const EdgeInsetsDirectional.only(
|
||||||
|
start: startPadding,
|
||||||
|
end: endPadding,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(sliderRenderBox().size, const Size(800 - startPadding - endPadding, 20));
|
||||||
|
expect(
|
||||||
|
find.byType(Slider),
|
||||||
|
paints
|
||||||
|
// Inactive track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(338.0, 8.0, 680.0, 12.0, const Radius.circular(2.0)),
|
||||||
|
)
|
||||||
|
// Active track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(0.0, 7.0, 342.0, 13.0, const Radius.circular(3.0)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Test Slider height and tracks spacing with top and bottom padding.
|
||||||
|
const double topPadding = 100;
|
||||||
|
const double bottomPadding = 20;
|
||||||
|
const double trackHeight = 20;
|
||||||
|
await tester.pumpWidget(buildSlider(padding: const EdgeInsetsDirectional.only(top: topPadding, bottom: bottomPadding)));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(tester.getSize(find.byType(Slider)), const Size(800, topPadding + trackHeight + bottomPadding));
|
||||||
|
expect(sliderRenderBox().size, const Size(800, 20));
|
||||||
|
expect(
|
||||||
|
find.byType(Slider),
|
||||||
|
paints
|
||||||
|
// Inactive track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(398.0, 8.0, 800.0, 12.0, const Radius.circular(2.0)),
|
||||||
|
)
|
||||||
|
// Active track.
|
||||||
|
..rrect(
|
||||||
|
rrect: RRect.fromLTRBR(0.0, 7.0, 402.0, 13.0, const Radius.circular(3.0)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
group('Material 2', () {
|
group('Material 2', () {
|
||||||
// These tests are only relevant for Material 2. Once Material 2
|
// These tests are only relevant for Material 2. Once Material 2
|
||||||
// support is deprecated and the APIs are removed, these tests
|
// support is deprecated and the APIs are removed, these tests
|
||||||
|
Loading…
x
Reference in New Issue
Block a user