Unverified Commit 96f15c74 authored by Anthony's avatar Anthony Committed by GitHub

[Material] Update slider and slider theme with new sizes, shapes, and color...

[Material] Update slider and slider theme with new sizes, shapes, and color mappings (2nd attempt) (#31564)

#30390 was rolled back. This PR will re-roll it forward.

This PR makes a number of changes to the visual appearance of material sliders:

Sizes/Shapes
** enabled thumb radius from 6 to 10
** disabled thumb radius from 4 to 10 with no gap
** default track shape is a rounded rect rather than a rect
**
Colors
** all of the colors now use the new color scheme
** overlay opacity has been reduce from 16% to 12%
** value indicator text color now respects the indicator it is on by using onPrimary
** disabledThumb color no respects the surface it is on by using onSurface
The slider theme is also now constructed consistently with other theme objects within the ThemeData. By default, all values are null, and have default values that are resolved in the slider itself, rather than in the slider theme.
parent b27b3d74
......@@ -428,27 +428,52 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
return widget.max > widget.min ? (value - widget.min) / (widget.max - widget.min) : 0.0;
}
static const double _defaultTrackHeight = 2;
static const SliderTrackShape _defaultTrackShape = RoundedRectSliderTrackShape();
static const SliderTickMarkShape _defaultTickMarkShape = RoundSliderTickMarkShape();
static const SliderComponentShape _defaultOverlayShape = RoundSliderOverlayShape();
static const SliderComponentShape _defaultThumbShape = RoundSliderThumbShape();
static const SliderComponentShape _defaultValueIndicatorShape = PaddleSliderValueIndicatorShape();
static const ShowValueIndicator _defaultShowValueIndicator = ShowValueIndicator.onlyForDiscrete;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
assert(debugCheckHasMediaQuery(context));
final ThemeData theme = Theme.of(context);
SliderThemeData sliderTheme = SliderTheme.of(context);
// If the widget has active or inactive colors specified, then we plug them
// in to the slider theme as best we can. If the developer wants more
// control than that, then they need to use a SliderTheme.
if (widget.activeColor != null || widget.inactiveColor != null) {
sliderTheme = sliderTheme.copyWith(
activeTrackColor: widget.activeColor,
inactiveTrackColor: widget.inactiveColor,
activeTickMarkColor: widget.inactiveColor,
inactiveTickMarkColor: widget.activeColor,
thumbColor: widget.activeColor,
valueIndicatorColor: widget.activeColor,
overlayColor: widget.activeColor?.withAlpha(0x29),
);
}
// control than that, then they need to use a SliderTheme. The default
// colors come from the ThemeData.colorScheme. These colors, along with
// the default shapes and text styles are aligned to the Material
// Guidelines.
sliderTheme = sliderTheme.copyWith(
trackHeight: sliderTheme.trackHeight ?? _defaultTrackHeight,
activeTrackColor: widget.activeColor ?? sliderTheme.activeTrackColor ?? theme.colorScheme.primary,
inactiveTrackColor: widget.inactiveColor ?? sliderTheme.inactiveTrackColor ?? theme.colorScheme.primary.withOpacity(0.24),
disabledActiveTrackColor: sliderTheme.disabledActiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.32),
disabledInactiveTrackColor: sliderTheme.disabledInactiveTrackColor ?? theme.colorScheme.onSurface.withOpacity(0.12),
activeTickMarkColor: widget.inactiveColor ?? sliderTheme.activeTickMarkColor ?? theme.colorScheme.onPrimary.withOpacity(0.54),
inactiveTickMarkColor: widget.activeColor ?? sliderTheme.inactiveTickMarkColor ?? theme.colorScheme.primary.withOpacity(0.54),
disabledActiveTickMarkColor: sliderTheme.disabledActiveTickMarkColor ?? theme.colorScheme.onPrimary.withOpacity(0.12),
disabledInactiveTickMarkColor: sliderTheme.disabledInactiveTickMarkColor ?? theme.colorScheme.onSurface.withOpacity(0.12),
thumbColor: widget.activeColor ?? sliderTheme.thumbColor ?? theme.colorScheme.primary,
disabledThumbColor: sliderTheme.disabledThumbColor ?? theme.colorScheme.onSurface.withOpacity(0.38),
overlayColor: widget.activeColor?.withOpacity(0.12) ?? sliderTheme.overlayColor ?? theme.colorScheme.primary.withOpacity(0.12),
valueIndicatorColor: widget.activeColor ?? sliderTheme.valueIndicatorColor ?? theme.colorScheme.primary,
trackShape: sliderTheme.trackShape ?? _defaultTrackShape,
tickMarkShape: sliderTheme.tickMarkShape ?? _defaultTickMarkShape,
thumbShape: sliderTheme.thumbShape ?? _defaultThumbShape,
overlayShape: sliderTheme.overlayShape ?? _defaultOverlayShape,
valueIndicatorShape: sliderTheme.valueIndicatorShape ?? _defaultValueIndicatorShape,
showValueIndicator: sliderTheme.showValueIndicator ?? _defaultShowValueIndicator,
valueIndicatorTextStyle: sliderTheme.valueIndicatorTextStyle ?? theme.textTheme.body2.copyWith(
color: theme.colorScheme.onPrimary,
),
);
return _SliderRenderObjectWidget(
value: _unlerp(widget.value),
......@@ -498,7 +523,6 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
divisions: divisions,
label: label,
sliderTheme: sliderTheme,
theme: Theme.of(context),
mediaQueryData: mediaQueryData,
onChanged: onChanged,
onChangeStart: onChangeStart,
......@@ -536,7 +560,6 @@ class _RenderSlider extends RenderBox {
int divisions,
String label,
SliderThemeData sliderTheme,
ThemeData theme,
MediaQueryData mediaQueryData,
TargetPlatform platform,
ValueChanged<double> onChanged,
......@@ -554,7 +577,6 @@ class _RenderSlider extends RenderBox {
_value = value,
_divisions = divisions,
_sliderTheme = sliderTheme,
_theme = theme,
_mediaQueryData = mediaQueryData,
_onChanged = onChanged,
_state = state,
......@@ -983,7 +1005,6 @@ class _RenderSlider extends RenderBox {
isEnabled: isInteractive,
);
// TODO(closkmith): Move this to paint after the thumb.
if (!_overlayAnimation.isDismissed) {
_sliderTheme.overlayShape.paint(
context,
......@@ -1000,7 +1021,6 @@ class _RenderSlider extends RenderBox {
}
if (isDiscrete) {
// TODO(clocksmith): Align tick mark centers to ends of track by not subtracting diameter from length.
final double tickMarkWidth = _sliderTheme.tickMarkShape.getPreferredSize(
isEnabled: isInteractive,
sliderTheme: _sliderTheme,
......
......@@ -210,46 +210,27 @@ class SliderThemeData extends Diagnosticable {
/// ```
/// {@end-tool}
const SliderThemeData({
@required this.trackHeight,
@required this.activeTrackColor,
@required this.inactiveTrackColor,
@required this.disabledActiveTrackColor,
@required this.disabledInactiveTrackColor,
@required this.activeTickMarkColor,
@required this.inactiveTickMarkColor,
@required this.disabledActiveTickMarkColor,
@required this.disabledInactiveTickMarkColor,
@required this.thumbColor,
@required this.disabledThumbColor,
@required this.overlayColor,
@required this.valueIndicatorColor,
@required this.trackShape,
@required this.tickMarkShape,
@required this.thumbShape,
@required this.overlayShape,
@required this.valueIndicatorShape,
@required this.showValueIndicator,
@required this.valueIndicatorTextStyle,
}) : assert(trackHeight != null),
assert(activeTrackColor != null),
assert(inactiveTrackColor != null),
assert(disabledActiveTrackColor != null),
assert(disabledInactiveTrackColor != null),
assert(activeTickMarkColor != null),
assert(inactiveTickMarkColor != null),
assert(disabledActiveTickMarkColor != null),
assert(disabledInactiveTickMarkColor != null),
assert(thumbColor != null),
assert(disabledThumbColor != null),
assert(overlayColor != null),
assert(valueIndicatorColor != null),
assert(trackShape != null),
assert(tickMarkShape != null),
assert(thumbShape != null),
assert(overlayShape != null),
assert(valueIndicatorShape != null),
assert(valueIndicatorTextStyle != null),
assert(showValueIndicator != null);
this.trackHeight,
this.activeTrackColor,
this.inactiveTrackColor,
this.disabledActiveTrackColor,
this.disabledInactiveTrackColor,
this.activeTickMarkColor,
this.inactiveTickMarkColor,
this.disabledActiveTickMarkColor,
this.disabledInactiveTickMarkColor,
this.thumbColor,
this.disabledThumbColor,
this.overlayColor,
this.valueIndicatorColor,
this.trackShape,
this.tickMarkShape,
this.thumbShape,
this.overlayShape,
this.valueIndicatorShape,
this.showValueIndicator,
this.valueIndicatorTextStyle,
});
/// Generates a SliderThemeData from three main colors.
///
......@@ -283,15 +264,9 @@ class SliderThemeData extends Diagnosticable {
const int disabledInactiveTickMarkAlpha = 0x1f; // 12% opacity
const int thumbAlpha = 0xff;
const int disabledThumbAlpha = 0x52; // 32% opacity
const int overlayAlpha = 0x1f; // 12% opacity
const int valueIndicatorAlpha = 0xff;
// TODO(gspencer): We don't really follow the spec here for overlays.
// The spec says to use 16% opacity for drawing over light material,
// and 32% for colored material, but we don't really have a way to
// know what the underlying color is, so there's no easy way to
// implement this. Choosing the "light" version for now.
const int overlayLightAlpha = 0x29; // 16% opacity
return SliderThemeData(
trackHeight: 2.0,
activeTrackColor: primaryColor.withAlpha(activeTrackAlpha),
......@@ -304,9 +279,9 @@ class SliderThemeData extends Diagnosticable {
disabledInactiveTickMarkColor: primaryColorDark.withAlpha(disabledInactiveTickMarkAlpha),
thumbColor: primaryColor.withAlpha(thumbAlpha),
disabledThumbColor: primaryColorDark.withAlpha(disabledThumbAlpha),
overlayColor: primaryColor.withAlpha(overlayLightAlpha),
overlayColor: primaryColor.withAlpha(overlayAlpha),
valueIndicatorColor: primaryColor.withAlpha(valueIndicatorAlpha),
trackShape: const RectangularSliderTrackShape(),
trackShape: const RoundedRectSliderTrackShape(),
tickMarkShape: const RoundSliderTickMarkShape(),
thumbShape: const RoundSliderThumbShape(),
overlayShape: const RoundSliderOverlayShape(),
......@@ -927,15 +902,151 @@ class _EmptySliderComponentShape extends SliderComponentShape {
}
}
// The following shapes are the material defaults.
/// Base track shape that provides an implementation of [getPreferredRect] for
/// default sizing.
///
/// See also:
///
/// * [RectangularSliderTrackShape], which is a track shape with sharp
/// rectangular edges
/// * [RoundedRectSliderTrackShape], which is a track shape with round
/// stadium-like edges.
///
/// The height is set from [SliderThemeData.trackHeight] and the width of the
/// parent box less the larger of the widths of [SliderThemeData.thumbShape] and
/// [SliderThemeData.overlayShape].
abstract class BaseSliderTrackShape {
/// Returns a rect that represents the track bounds that fits within the
/// [Slider].
///
/// The width is the width of the [Slider], but padded by the max
/// of the overlay and thumb radius. The height is defined by the
/// [SliderThemeData.trackHeight].
///
/// The [Rect] is centered both horizontally and vertically within the slider
/// bounds.
Rect getPreferredRect({
@required RenderBox parentBox,
Offset offset = Offset.zero,
SliderThemeData sliderTheme,
bool isEnabled = false,
bool isDiscrete = false,
}) {
assert(parentBox != null);
final double thumbWidth = sliderTheme.thumbShape.getPreferredSize(isEnabled, isDiscrete).width;
final double overlayWidth = sliderTheme.overlayShape.getPreferredSize(isEnabled, isDiscrete).width;
final double trackHeight = sliderTheme.trackHeight;
assert(overlayWidth >= 0);
assert(trackHeight >= 0);
assert(parentBox.size.width >= overlayWidth);
assert(parentBox.size.height >= trackHeight);
final double trackLeft = offset.dx + overlayWidth / 2;
final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
final double trackWidth = parentBox.size.width - math.max(thumbWidth, overlayWidth);
return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
}
}
/// This is the default shape of a [Slider]'s track.
///
/// It paints a solid colored rectangle with rounded edges, vertically centered
/// in the [parentBox]. The track rectangle extends to the bounds of the
/// [parentBox], but is padded by the larger of [RoundSliderOverlayShape]'s
/// radius and [RoundSliderThumbShape]'s radius. The height is defined by the
/// [SliderThemeData.trackHeight]. The color is determined by the [Slider]'s
/// enabled state and the track segment's active state which are defined by:
/// [SliderThemeData.activeTrackColor],
/// [SliderThemeData.inactiveTrackColor],
/// [SliderThemeData.disabledActiveTrackColor],
/// [SliderThemeData.disabledInactiveTrackColor].
///
/// See also:
///
/// * [Slider], for the component that is meant to display this shape.
/// * [SliderThemeData], where an instance of this class is set to inform the
/// slider of the visual details of the its track.
/// * [SliderTrackShape], which is the base component for creating other
/// custom track shapes.
/// * [RectangularSliderTrackShape], for a similar track with sharp edges.
class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackShape {
/// Create a slider track that draws two rectangles with rounded outer edges.
const RoundedRectSliderTrackShape();
@override
void paint(
PaintingContext context,
Offset offset, {
@required RenderBox parentBox,
@required SliderThemeData sliderTheme,
@required Animation<double> enableAnimation,
@required TextDirection textDirection,
@required Offset thumbCenter,
bool isDiscrete = false,
bool isEnabled = false,
}) {
assert(context != null);
assert(offset != null);
assert(parentBox != null);
assert(sliderTheme != null);
assert(enableAnimation != null);
assert(textDirection != null);
assert(thumbCenter != null);
// If the slider track height is less than or equal to 0, then it makes no
// difference whether the track is painted or not, therefore the painting
// can be a no-op.
if (sliderTheme.trackHeight <= 0) {
return;
}
// Assign the track segment paints, which are leading: active and
// trailing: inactive.
final ColorTween activeTrackColorTween = ColorTween(begin: sliderTheme.disabledActiveTrackColor, end: sliderTheme.activeTrackColor);
final ColorTween inactiveTrackColorTween = ColorTween(begin: sliderTheme.disabledInactiveTrackColor, end: sliderTheme.inactiveTrackColor);
final Paint activePaint = Paint()..color = activeTrackColorTween.evaluate(enableAnimation);
final Paint inactivePaint = Paint()..color = inactiveTrackColorTween.evaluate(enableAnimation);
Paint leftTrackPaint;
Paint rightTrackPaint;
switch (textDirection) {
case TextDirection.ltr:
leftTrackPaint = activePaint;
rightTrackPaint = inactivePaint;
break;
case TextDirection.rtl:
leftTrackPaint = inactivePaint;
rightTrackPaint = activePaint;
break;
}
final Rect trackRect = getPreferredRect(
parentBox: parentBox,
offset: offset,
sliderTheme: sliderTheme,
isEnabled: isEnabled,
isDiscrete: isDiscrete,
);
// The arc rects create a semi-circle with radius equal to track height.
final Rect leftTrackArcRect = Rect.fromLTWH(trackRect.left, trackRect.top, trackRect.height, trackRect.height);
context.canvas.drawArc(leftTrackArcRect, math.pi / 2, math.pi, false, leftTrackPaint);
final Rect rightTrackArcRect = Rect.fromLTWH(trackRect.right - trackRect.height / 2, trackRect.top, trackRect.height, trackRect.height);
context.canvas.drawArc(rightTrackArcRect, -math.pi / 2, math.pi, false, rightTrackPaint);
final Size thumbSize = sliderTheme.thumbShape.getPreferredSize(isEnabled, isDiscrete);
final Rect leftTrackSegment = Rect.fromLTRB(trackRect.left + trackRect.height / 2, trackRect.top, thumbCenter.dx - thumbSize.width / 2, trackRect.bottom);
context.canvas.drawRect(leftTrackSegment, leftTrackPaint);
final Rect rightTrackSegment = Rect.fromLTRB(thumbCenter.dx + thumbSize.width / 2, trackRect.top, trackRect.right, trackRect.bottom);
context.canvas.drawRect(rightTrackSegment, rightTrackPaint);
}
}
/// A [Slider] track that's a simple rectangle.
///
/// It paints a solid colored rectangle, vertically centered in the
/// [parentBox]. The track rectangle extends to the bounds of the [parentBox],
/// but is padded by the [RoundSliderOverlayShape] radius. The height is defined
/// by the [SliderThemeData.trackHeight]. The color is determined by the
/// [Slider]'s enabled state and the track piece's active state which are
/// [Slider]'s enabled state and the track segments's active state which are
/// defined by:
/// [SliderThemeData.activeTrackColor],
/// [SliderThemeData.inactiveTrackColor],
......@@ -944,11 +1055,12 @@ class _EmptySliderComponentShape extends SliderComponentShape {
///
/// See also:
///
/// * [Slider] for the component that this is meant to display this shape.
/// * [SliderThemeData] where an instance of this class is set to inform the
/// * [Slider], for the component that is meant to display this shape.
/// * [SliderThemeData], where an instance of this class is set to inform the
/// slider of the visual details of the its track.
/// * [SliderTrackShape] Base component for creating other custom track
/// shapes.
/// * [SliderTrackShape], which is the base component for creating other
/// custom track shapes.
/// * [RoundedRectSliderTrackShape], for a similar track with rounded edges.
class RectangularSliderTrackShape extends SliderTrackShape {
/// Create a slider track that draws 2 rectangles.
const RectangularSliderTrackShape({ this.disabledThumbGapWidth = 2.0 });
......@@ -963,12 +1075,15 @@ class RectangularSliderTrackShape extends SliderTrackShape {
@override
Rect getPreferredRect({
RenderBox parentBox,
@required RenderBox parentBox,
Offset offset = Offset.zero,
SliderThemeData sliderTheme,
bool isEnabled,
bool isDiscrete,
@required SliderThemeData sliderTheme,
bool isEnabled = false,
bool isDiscrete = false,
}) {
assert(parentBox != null);
assert(sliderTheme != null);
final double thumbWidth = sliderTheme.thumbShape.getPreferredSize(isEnabled, isDiscrete).width;
final double overlayWidth = sliderTheme.overlayShape.getPreferredSize(isEnabled, isDiscrete).width;
final double trackHeight = sliderTheme.trackHeight;
assert(overlayWidth >= 0);
......@@ -978,29 +1093,33 @@ class RectangularSliderTrackShape extends SliderTrackShape {
final double trackLeft = offset.dx + overlayWidth / 2;
final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
// TODO(clocksmith): Although this works for a material, perhaps the default
// rectangular track should be padded not just by the overlay, but by the
// max of the thumb and the overlay, in case there is no overlay.
final double trackWidth = parentBox.size.width - overlayWidth;
final double trackWidth = parentBox.size.width - math.max(thumbWidth, overlayWidth);
return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
}
@override
void paint(
PaintingContext context,
Offset offset, {
RenderBox parentBox,
SliderThemeData sliderTheme,
Animation<double> enableAnimation,
TextDirection textDirection,
Offset thumbCenter,
bool isDiscrete,
bool isEnabled,
@required RenderBox parentBox,
@required SliderThemeData sliderTheme,
@required Animation<double> enableAnimation,
@required TextDirection textDirection,
@required Offset thumbCenter,
bool isDiscrete = false,
bool isEnabled = false,
}) {
// If the slider track height is 0, then it makes no difference whether the
// track is painted or not, therefore the painting can be a no-op.
if (sliderTheme.trackHeight == 0) {
assert(context != null);
assert(offset != null);
assert(parentBox != null);
assert(sliderTheme != null);
assert(enableAnimation != null);
assert(textDirection != null);
assert(thumbCenter != null);
// If the slider track height is less than or equal to 0, then it makes no
// difference whether the track is painted or not, therefore the painting
// can be a no-op.
if (sliderTheme.trackHeight <= 0) {
return;
}
......@@ -1023,28 +1142,18 @@ class RectangularSliderTrackShape extends SliderTrackShape {
break;
}
// Used to create a gap around the thumb iff the slider is disabled.
// If the slider is enabled, the track can be drawn beneath the thumb
// without a gap. But when the slider is disabled, the track is shortened
// and this gap helps determine how much shorter it should be.
// TODO(clocksmith): The new Material spec has a gray circle in place of this gap.
double horizontalAdjustment = 0.0;
if (!isEnabled) {
final double disabledThumbRadius = sliderTheme.thumbShape.getPreferredSize(false, isDiscrete).width / 2.0;
final double gap = disabledThumbGapWidth * (1.0 - enableAnimation.value);
horizontalAdjustment = disabledThumbRadius + gap;
}
final Rect trackRect = getPreferredRect(
parentBox: parentBox,
offset: offset,
sliderTheme: sliderTheme,
isEnabled: isEnabled,
isDiscrete: isDiscrete,
parentBox: parentBox,
offset: offset,
sliderTheme: sliderTheme,
isEnabled: isEnabled,
isDiscrete: isDiscrete,
);
final Rect leftTrackSegment = Rect.fromLTRB(trackRect.left, trackRect.top, thumbCenter.dx - horizontalAdjustment, trackRect.bottom);
final Size thumbSize = sliderTheme.thumbShape.getPreferredSize(isEnabled, isDiscrete);
final Rect leftTrackSegment = Rect.fromLTRB(trackRect.left + trackRect.height / 2, trackRect.top, thumbCenter.dx - thumbSize.width / 2, trackRect.bottom);
context.canvas.drawRect(leftTrackSegment, leftTrackPaint);
final Rect rightTrackSegment = Rect.fromLTRB(thumbCenter.dx + horizontalAdjustment, trackRect.top, trackRect.right, trackRect.bottom);
final Rect rightTrackSegment = Rect.fromLTRB(thumbCenter.dx + thumbSize.width / 2, trackRect.top, trackRect.right, trackRect.bottom);
context.canvas.drawRect(rightTrackSegment, rightTrackPaint);
}
}
......@@ -1090,13 +1199,20 @@ class RoundSliderTickMarkShape extends SliderTickMarkShape {
void paint(
PaintingContext context,
Offset center, {
RenderBox parentBox,
SliderThemeData sliderTheme,
Animation<double> enableAnimation,
TextDirection textDirection,
Offset thumbCenter,
bool isEnabled,
@required RenderBox parentBox,
@required SliderThemeData sliderTheme,
@required Animation<double> enableAnimation,
@required TextDirection textDirection,
@required Offset thumbCenter,
bool isEnabled = false,
}) {
assert(context != null);
assert(center != null);
assert(parentBox != null);
assert(sliderTheme != null);
assert(enableAnimation != null);
assert(textDirection != null);
assert(thumbCenter != null);
// The paint color of the tick mark depends on its position relative
// to the thumb and the text direction.
Color begin;
......@@ -1133,26 +1249,22 @@ class RoundSliderTickMarkShape extends SliderTickMarkShape {
/// sliders in a widget subtree.
class RoundSliderThumbShape extends SliderComponentShape {
/// Create a slider thumb that draws a circle.
// TODO(clocksmith): This needs to be changed to 10 according to spec.
const RoundSliderThumbShape({
this.enabledThumbRadius = 6.0,
this.enabledThumbRadius = 10.0,
this.disabledThumbRadius,
});
/// The preferred radius of the round thumb shape when the slider is enabled.
///
/// If it is not provided, then the material default is used.
/// If it is not provided, then the material default of 10 is used.
final double enabledThumbRadius;
/// The preferred radius of the round thumb shape when the slider is disabled.
///
/// If no disabledRadius is provided, then it is is derived from the enabled
/// thumb radius and has the same ratio of enabled size to disabled size as
/// the Material spec. The default resolves to 4, which is 2 / 3 of the
/// default enabled thumb.
/// If no disabledRadius is provided, then it is equal to the
/// [enabledThumbRadius]
final double disabledThumbRadius;
// TODO(clocksmith): This needs to be updated once the thumb size is updated to the Material spec.
double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius * 2 / 3;
double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius;
@override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
......@@ -1163,15 +1275,24 @@ class RoundSliderThumbShape extends SliderComponentShape {
void paint(
PaintingContext context,
Offset center, {
Animation<double> activationAnimation,
Animation<double> enableAnimation,
bool isDiscrete,
TextPainter labelPainter,
RenderBox parentBox,
SliderThemeData sliderTheme,
TextDirection textDirection,
double value,
@required Animation<double> activationAnimation,
@required Animation<double> enableAnimation,
bool isDiscrete = false,
@required TextPainter labelPainter,
@required RenderBox parentBox,
@required SliderThemeData sliderTheme,
@required TextDirection textDirection,
@required double value,
}) {
assert(context != null);
assert(center != null);
assert(activationAnimation != null);
assert(enableAnimation != null);
assert(labelPainter != null);
assert(parentBox != null);
assert(sliderTheme != null);
assert(textDirection != null);
assert(value != null);
final Canvas canvas = context.canvas;
final Tween<double> radiusTween = Tween<double>(
begin: _disabledThumbRadius,
......@@ -1206,8 +1327,7 @@ class RoundSliderThumbShape extends SliderComponentShape {
/// sliders in a widget subtree.
class RoundSliderOverlayShape extends SliderComponentShape {
/// Create a slider thumb overlay that draws a circle.
// TODO(clocksmith): This needs to be changed to 24 according to spec.
const RoundSliderOverlayShape({ this.overlayRadius = 16.0 });
const RoundSliderOverlayShape({ this.overlayRadius = 24.0 });
/// The preferred radius of the round thumb shape when enabled.
///
......@@ -1223,26 +1343,30 @@ class RoundSliderOverlayShape extends SliderComponentShape {
void paint(
PaintingContext context,
Offset center, {
Animation<double> activationAnimation,
Animation<double> enableAnimation,
bool isDiscrete,
TextPainter labelPainter,
RenderBox parentBox,
SliderThemeData sliderTheme,
TextDirection textDirection,
double value,
@required Animation<double> activationAnimation,
@required Animation<double> enableAnimation,
bool isDiscrete = false,
@required TextPainter labelPainter,
@required RenderBox parentBox,
@required SliderThemeData sliderTheme,
@required TextDirection textDirection,
@required double value,
}) {
assert(context != null);
assert(center != null);
assert(activationAnimation != null);
assert(enableAnimation != null);
assert(labelPainter != null);
assert(parentBox != null);
assert(sliderTheme != null);
assert(textDirection != null);
assert(value != null);
final Canvas canvas = context.canvas;
final Tween<double> radiusTween = Tween<double>(
begin: 0.0,
end: overlayRadius,
);
// TODO(gspencer): We don't really follow the spec here for overlays.
// The spec says to use 16% opacity for drawing over light material,
// and 32% for colored material, but we don't really have a way to
// know what the underlying color is, so there's no easy way to
// implement this. Choosing the "light" version for now.
canvas.drawCircle(
center,
radiusTween.evaluate(activationAnimation),
......@@ -1324,7 +1448,7 @@ class PaddleSliderValueIndicatorShape extends SliderComponentShape {
final Path path = Path();
final Offset bottomKnobStart = Offset(
_bottomLobeRadius * math.cos(_bottomLobeStartAngle),
_bottomLobeRadius * math.sin(_bottomLobeStartAngle),
_bottomLobeRadius * math.sin(_bottomLobeStartAngle) - 2,
);
final Offset bottomNeckRightCenter = bottomKnobStart +
Offset(
......@@ -1474,7 +1598,7 @@ class PaddleSliderValueIndicatorShape extends SliderComponentShape {
// The distance between the end of the bottom neck arc and the beginning of
// the top neck arc. We use this to shrink/expand it based on the scale
// factor of the value indicator.
final double neckStretchBaseline = bottomLobeEnd.dy - math.max(neckLeftCenter.dy, neckRightCenter.dy);
final double neckStretchBaseline = math.max(0.0, bottomLobeEnd.dy - math.max(neckLeftCenter.dy, neckRightCenter.dy));
final double t = math.pow(inverseTextScale, 3.0);
final double stretch = (neckStretchBaseline * t).clamp(0.0, 10.0 * neckStretchBaseline);
final Offset neckStretch = Offset(0.0, neckStretchBaseline - stretch);
......@@ -1540,15 +1664,24 @@ class PaddleSliderValueIndicatorShape extends SliderComponentShape {
void paint(
PaintingContext context,
Offset center, {
Animation<double> activationAnimation,
Animation<double> enableAnimation,
bool isDiscrete,
TextPainter labelPainter,
RenderBox parentBox,
SliderThemeData sliderTheme,
TextDirection textDirection,
double value,
@required Animation<double> activationAnimation,
@required Animation<double> enableAnimation,
bool isDiscrete = false,
@required TextPainter labelPainter,
@required RenderBox parentBox,
@required SliderThemeData sliderTheme,
@required TextDirection textDirection,
@required double value,
}) {
assert(context != null);
assert(center != null);
assert(activationAnimation != null);
assert(enableAnimation != null);
assert(labelPainter != null);
assert(parentBox != null);
assert(sliderTheme != null);
assert(textDirection != null);
assert(value != null);
final ColorTween enableColor = ColorTween(
begin: sliderTheme.disabledThumbColor,
end: sliderTheme.valueIndicatorColor,
......
......@@ -243,12 +243,7 @@ class ThemeData extends Diagnosticable {
highlightColor ??= isDark ? _kDarkThemeHighlightColor : _kLightThemeHighlightColor;
splashColor ??= isDark ? _kDarkThemeSplashColor : _kLightThemeSplashColor;
sliderTheme ??= SliderThemeData.fromPrimaryColors(
primaryColor: primaryColor,
primaryColorLight: primaryColorLight,
primaryColorDark: primaryColorDark,
valueIndicatorTextStyle: accentTextTheme.body2,
);
sliderTheme ??= const SliderThemeData();
tabBarTheme ??= const TabBarTheme();
appBarTheme ??= const AppBarTheme();
bottomAppBarTheme ??= const BottomAppBarTheme();
......
......@@ -298,8 +298,8 @@ void main() {
);
final List<Offset> expectedLog = <Offset>[
const Offset(16.0, 300.0),
const Offset(16.0, 300.0),
const Offset(24.0, 300.0),
const Offset(24.0, 300.0),
const Offset(400.0, 300.0),
];
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byKey(sliderKey)));
......@@ -313,20 +313,20 @@ void main() {
await tester.pump(const Duration(milliseconds: 10));
expect(value, equals(0.0));
expect(log.length, 5);
expect(log.last.dx, closeTo(386.3, 0.1));
expect(log.last.dx, closeTo(386.6, 0.1));
// With no more gesture or value changes, the thumb position should still
// be redrawn in the animated position.
await tester.pump();
await tester.pump(const Duration(milliseconds: 10));
expect(value, equals(0.0));
expect(log.length, 7);
expect(log.last.dx, closeTo(343.3, 0.1));
expect(log.last.dx, closeTo(344.5, 0.1));
// Final position.
await tester.pump(const Duration(milliseconds: 80));
expectedLog.add(const Offset(16.0, 300.0));
expectedLog.add(const Offset(24.0, 300.0));
expect(value, equals(0.0));
expect(log.length, 8);
expect(log.last.dx, closeTo(16.0, 0.1));
expect(log.last.dx, closeTo(24.0, 0.1));
await gesture.up();
});
......@@ -409,8 +409,8 @@ void main() {
);
final List<Offset> expectedLog = <Offset>[
const Offset(16.0, 300.0),
const Offset(16.0, 300.0),
const Offset(24.0, 300.0),
const Offset(24.0, 300.0),
const Offset(400.0, 300.0),
];
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byKey(sliderKey)));
......@@ -424,20 +424,20 @@ void main() {
await tester.pump(const Duration(milliseconds: 10));
expect(value, equals(0.0));
expect(log.length, 5);
expect(log.last.dx, closeTo(386.3, 0.1));
expect(log.last.dx, closeTo(386.6, 0.1));
// With no more gesture or value changes, the thumb position should still
// be redrawn in the animated position.
await tester.pump();
await tester.pump(const Duration(milliseconds: 10));
expect(value, equals(0.0));
expect(log.length, 7);
expect(log.last.dx, closeTo(343.3, 0.1));
expect(log.last.dx, closeTo(344.5, 0.1));
// Final position.
await tester.pump(const Duration(milliseconds: 80));
expectedLog.add(const Offset(16.0, 300.0));
expectedLog.add(const Offset(24.0, 300.0));
expect(value, equals(0.0));
expect(log.length, 8);
expect(log.last.dx, closeTo(16.0, 0.1));
expect(log.last.dx, closeTo(24.0, 0.1));
await gesture.up();
});
......@@ -546,6 +546,20 @@ void main() {
final ThemeData theme = ThemeData(
platform: TargetPlatform.android,
primarySwatch: Colors.blue,
sliderTheme: const SliderThemeData(
disabledThumbColor: Color(0xff000001),
disabledActiveTickMarkColor: Color(0xff000002),
disabledActiveTrackColor: Color(0xff000003),
disabledInactiveTickMarkColor: Color(0xff000004),
disabledInactiveTrackColor: Color(0xff000005),
activeTrackColor: Color(0xff000006),
activeTickMarkColor: Color(0xff000007),
inactiveTrackColor: Color(0xff000008),
inactiveTickMarkColor: Color(0xff000009),
overlayColor: Color(0xff000010),
thumbColor: Color(0xff000011),
valueIndicatorColor: Color(0xff000012),
)
);
final SliderThemeData sliderTheme = theme.sliderTheme;
double value = 0.45;
......@@ -724,7 +738,7 @@ void main() {
paints
..rect(color: customColor1) // active track
..rect(color: customColor2) // inactive track
..circle(color: customColor1.withAlpha(0x29)) // overlay
..circle(color: customColor1.withOpacity(0.12)) // overlay
..circle(color: customColor2) // 1st tick mark
..circle(color: customColor2) // 2nd tick mark
..circle(color: customColor2) // 3rd tick mark
......@@ -858,7 +872,7 @@ void main() {
),
),
));
expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(144.0 + 2.0 * 16.0, 600.0));
expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(144.0 + 2.0 * 24.0, 600.0));
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
......@@ -878,7 +892,7 @@ void main() {
),
),
));
expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(144.0 + 2.0 * 16.0, 32.0));
expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(144.0 + 2.0 * 24.0, 48.0));
});
testWidgets('Slider respects textScaleFactor', (WidgetTester tester) async {
......@@ -1077,12 +1091,12 @@ void main() {
expect(
sliderBox,
paints
..circle(x: 17.0, y: 16.0, radius: 1.0)
..circle(x: 208.5, y: 16.0, radius: 1.0)
..circle(x: 400.0, y: 16.0, radius: 1.0)
..circle(x: 591.5, y: 16.0, radius: 1.0)
..circle(x: 783.0, y: 16.0, radius: 1.0)
..circle(x: 16.0, y: 16.0, radius: 6.0),
..circle(x: 25.0, y: 24.0, radius: 1.0)
..circle(x: 212.5, y: 24.0, radius: 1.0)
..circle(x: 400.0, y: 24.0, radius: 1.0)
..circle(x: 587.5, y: 24.0, radius: 1.0)
..circle(x: 775.0, y: 24.0, radius: 1.0)
..circle(x: 24.0, y: 24.0, radius: 10.0),
);
gesture = await tester.startGesture(center);
......@@ -1093,13 +1107,13 @@ void main() {
expect(
sliderBox,
paints
..circle(x: 105.0625, y: 16.0, radius: 3.791776657104492)
..circle(x: 17.0, y: 16.0, radius: 1.0)
..circle(x: 208.5, y: 16.0, radius: 1.0)
..circle(x: 400.0, y: 16.0, radius: 1.0)
..circle(x: 591.5, y: 16.0, radius: 1.0)
..circle(x: 783.0, y: 16.0, radius: 1.0)
..circle(x: 105.0625, y: 16.0, radius: 6.0),
..circle(x: 111.20703125, y: 24.0, radius: 5.687664985656738)
..circle(x: 25.0, y: 24.0, radius: 1.0)
..circle(x: 212.5, y: 24.0, radius: 1.0)
..circle(x: 400.0, y: 24.0, radius: 1.0)
..circle(x: 587.5, y: 24.0, radius: 1.0)
..circle(x: 775.0, y: 24.0, radius: 1.0)
..circle(x: 111.20703125, y: 24.0, radius: 10.0),
);
// Reparenting in the middle of an animation should do nothing.
......@@ -1113,13 +1127,13 @@ void main() {
expect(
sliderBox,
paints
..circle(x: 185.5457763671875, y: 16.0, radius: 8.0)
..circle(x: 17.0, y: 16.0, radius: 1.0)
..circle(x: 208.5, y: 16.0, radius: 1.0)
..circle(x: 400.0, y: 16.0, radius: 1.0)
..circle(x: 591.5, y: 16.0, radius: 1.0)
..circle(x: 783.0, y: 16.0, radius: 1.0)
..circle(x: 185.5457763671875, y: 16.0, radius: 6.0),
..circle(x: 190.0135726928711, y: 24.0, radius: 12.0)
..circle(x: 25.0, y: 24.0, radius: 1.0)
..circle(x: 212.5, y: 24.0, radius: 1.0)
..circle(x: 400.0, y: 24.0, radius: 1.0)
..circle(x: 587.5, y: 24.0, radius: 1.0)
..circle(x: 775.0, y: 24.0, radius: 1.0)
..circle(x: 190.0135726928711, y: 24.0, radius: 10.0),
);
// Wait for animations to finish.
await tester.pumpAndSettle();
......@@ -1127,13 +1141,13 @@ void main() {
expect(
sliderBox,
paints
..circle(x: 400.0, y: 16.0, radius: 16.0)
..circle(x: 17.0, y: 16.0, radius: 1.0)
..circle(x: 208.5, y: 16.0, radius: 1.0)
..circle(x: 400.0, y: 16.0, radius: 1.0)
..circle(x: 591.5, y: 16.0, radius: 1.0)
..circle(x: 783.0, y: 16.0, radius: 1.0)
..circle(x: 400.0, y: 16.0, radius: 6.0),
..circle(x: 400.0, y: 24.0, radius: 24.0)
..circle(x: 25.0, y: 24.0, radius: 1.0)
..circle(x: 212.5, y: 24.0, radius: 1.0)
..circle(x: 400.0, y: 24.0, radius: 1.0)
..circle(x: 587.5, y: 24.0, radius: 1.0)
..circle(x: 775.0, y: 24.0, radius: 1.0)
..circle(x: 400.0, y: 24.0, radius: 10.0),
);
await gesture.up();
await tester.pumpAndSettle();
......@@ -1141,12 +1155,12 @@ void main() {
expect(
sliderBox,
paints
..circle(x: 17.0, y: 16.0, radius: 1.0)
..circle(x: 208.5, y: 16.0, radius: 1.0)
..circle(x: 400.0, y: 16.0, radius: 1.0)
..circle(x: 591.5, y: 16.0, radius: 1.0)
..circle(x: 783.0, y: 16.0, radius: 1.0)
..circle(x: 400.0, y: 16.0, radius: 6.0),
..circle(x: 25.0, y: 24.0, radius: 1.0)
..circle(x: 212.5, y: 24.0, radius: 1.0)
..circle(x: 400.0, y: 24.0, radius: 1.0)
..circle(x: 587.5, y: 24.0, radius: 1.0)
..circle(x: 775.0, y: 24.0, radius: 1.0)
..circle(x: 400.0, y: 24.0, radius: 10.0),
);
}
......
......@@ -12,17 +12,6 @@ import 'package:flutter/painting.dart';
import '../rendering/mock_canvas.dart';
void main() {
testWidgets('Slider theme is built by ThemeData', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
platform: TargetPlatform.android,
primarySwatch: Colors.red,
);
final SliderThemeData sliderTheme = theme.sliderTheme;
expect(sliderTheme.activeTrackColor.value, equals(Colors.red.value));
expect(sliderTheme.inactiveTrackColor.value, equals(Colors.red.withAlpha(0x3d).value));
});
testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async {
final ThemeData theme = ThemeData(
platform: TargetPlatform.android,
......@@ -63,20 +52,6 @@ void main() {
);
});
testWidgets('SliderThemeData assigns the correct default shapes', (WidgetTester tester) async {
final SliderThemeData sliderTheme = ThemeData().sliderTheme;
expect(sliderTheme.trackShape, equals(isInstanceOf<RectangularSliderTrackShape>()));
expect(sliderTheme.tickMarkShape, equals(isInstanceOf<RoundSliderTickMarkShape>()));
expect(sliderTheme.thumbShape, equals(isInstanceOf<RoundSliderThumbShape>()));
expect(sliderTheme.valueIndicatorShape, equals(isInstanceOf<PaddleSliderValueIndicatorShape>()));
expect(sliderTheme.overlayShape, equals(isInstanceOf<RoundSliderOverlayShape>()));
});
testWidgets('SliderThemeData assigns the correct default flags', (WidgetTester tester) async {
final SliderThemeData sliderTheme = ThemeData().sliderTheme;
expect(sliderTheme.showValueIndicator, equals(ShowValueIndicator.onlyForDiscrete));
});
testWidgets('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async {
const Color customColor1 = Color(0xcafefeed);
const Color customColor2 = Color(0xdeadbeef);
......@@ -100,7 +75,7 @@ void main() {
expect(sliderTheme.disabledInactiveTickMarkColor, equals(customColor2.withAlpha(0x1f)));
expect(sliderTheme.thumbColor, equals(customColor1.withAlpha(0xff)));
expect(sliderTheme.disabledThumbColor, equals(customColor2.withAlpha(0x52)));
expect(sliderTheme.overlayColor, equals(customColor1.withAlpha(0x29)));
expect(sliderTheme.overlayColor, equals(customColor1.withAlpha(0x1f)));
expect(sliderTheme.valueIndicatorColor, equals(customColor1.withAlpha(0xff)));
expect(sliderTheme.valueIndicatorTextStyle.color, equals(customColor4));
});
......@@ -132,7 +107,7 @@ void main() {
expect(lerp.disabledInactiveTickMarkColor, equals(middleGrey.withAlpha(0x1f)));
expect(lerp.thumbColor, equals(middleGrey.withAlpha(0xff)));
expect(lerp.disabledThumbColor, equals(middleGrey.withAlpha(0x52)));
expect(lerp.overlayColor, equals(middleGrey.withAlpha(0x29)));
expect(lerp.overlayColor, equals(middleGrey.withAlpha(0x1f)));
expect(lerp.valueIndicatorColor, equals(middleGrey.withAlpha(0xff)));
expect(lerp.valueIndicatorTextStyle.color, equals(middleGrey.withAlpha(0xff)));
});
......@@ -152,8 +127,8 @@ void main() {
expect(
sliderBox,
paints
..rect(rect: Rect.fromLTRB(16.0, 299.0, 208.0, 301.0), color: sliderTheme.activeTrackColor)
..rect(rect: Rect.fromLTRB(208.0, 299.0, 784.0, 301.0), color: sliderTheme.inactiveTrackColor),
..rect(rect: Rect.fromLTRB(25.0, 299.0, 202.0, 301.0), color: sliderTheme.activeTrackColor)
..rect(rect: Rect.fromLTRB(222.0, 299.0, 776.0, 301.0), color: sliderTheme.inactiveTrackColor),
);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, enabled: false));
......@@ -168,8 +143,8 @@ void main() {
expect(
sliderBox,
paints
..rect(rect: Rect.fromLTRB(16.0, 299.0, 202.0, 301.0), color: sliderTheme.disabledActiveTrackColor)
..rect(rect: Rect.fromLTRB(214.0, 299.0, 784.0, 301.0), color: sliderTheme.disabledInactiveTrackColor),
..rect(rect: Rect.fromLTRB(25.0, 299.0, 202.0, 301.0), color: sliderTheme.disabledActiveTrackColor)
..rect(rect: Rect.fromLTRB(222.0, 299.0, 776.0, 301.0), color: sliderTheme.disabledInactiveTrackColor),
);
});
......@@ -189,9 +164,9 @@ void main() {
paints
..circle(
color: sliderTheme.thumbColor,
x: 208.0,
x: 212.0,
y: 300.0,
radius: 6.0,
radius: 10.0,
),
);
......@@ -206,15 +181,15 @@ void main() {
paints
..circle(
color: sliderTheme.overlayColor,
x: 208.0,
x: 212.0,
y: 300.0,
radius: 16.0,
radius: 24.0,
)
..circle(
color: sliderTheme.thumbColor,
x: 208.0,
x: 212.0,
y: 300.0,
radius: 6.0,
radius: 10.0,
),
);
......@@ -227,9 +202,9 @@ void main() {
paints
..circle(
color: sliderTheme.thumbColor,
x: 208.0,
x: 212.0,
y: 300.0,
radius: 6.0,
radius: 10.0,
),
);
});
......@@ -244,12 +219,12 @@ void main() {
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.45));
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
expect(sliderBox, paints..circle(color: sliderTheme.thumbColor, radius: 6.0));
expect(sliderBox, paints..circle(color: sliderTheme.thumbColor, radius: 10.0));
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.45, enabled: false));
await tester.pumpAndSettle(); // wait for disable animation
expect(sliderBox, paints..circle(color: sliderTheme.disabledThumbColor, radius: 4.0));
expect(sliderBox, paints..circle(color: sliderTheme.disabledThumbColor, radius: 10.0));
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.45, divisions: 3));
await tester.pumpAndSettle(); // wait for enable animation
......@@ -261,7 +236,7 @@ void main() {
..circle(color: sliderTheme.activeTickMarkColor)
..circle(color: sliderTheme.inactiveTickMarkColor)
..circle(color: sliderTheme.inactiveTickMarkColor)
..circle(color: sliderTheme.thumbColor, radius: 6.0),
..circle(color: sliderTheme.thumbColor, radius: 10.0),
);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.45, divisions: 3, enabled: false));
......@@ -274,7 +249,7 @@ void main() {
..circle(color: sliderTheme.disabledInactiveTickMarkColor)
..circle(color: sliderTheme.disabledInactiveTickMarkColor)
..circle(color: sliderTheme.disabledInactiveTickMarkColor)
..circle(color: sliderTheme.disabledThumbColor, radius: 4.0),
..circle(color: sliderTheme.disabledThumbColor, radius: 10.0),
);
});
......@@ -368,10 +343,10 @@ void main() {
color: sliderTheme.valueIndicatorColor,
includes: <Offset>[
const Offset(0.0, -40.0),
const Offset(98.0, -40.0),
const Offset(92.0, -40.0),
const Offset(-16.0, -40.0),
],
excludes: <Offset>[const Offset(98.1, -40.0), const Offset(-16.1, -40.0)],
excludes: <Offset>[const Offset(98.1, -40.0), const Offset(-20.1, -40.0)],
),
);
await gesture.up();
......@@ -390,9 +365,9 @@ void main() {
includes: <Offset>[
const Offset(0.0, -40.0),
const Offset(16.0, -40.0),
const Offset(-98.0, -40.0),
const Offset(-92.0, -40.0),
],
excludes: <Offset>[const Offset(16.1, -40.0), const Offset(-98.1, -40.0)],
excludes: <Offset>[const Offset(20.1, -40.0), const Offset(-98.1, -40.0)],
),
);
await gesture.up();
......@@ -410,14 +385,14 @@ void main() {
color: sliderTheme.valueIndicatorColor,
includes: <Offset>[
const Offset(0.0, -49.0),
const Offset(90.0, -49.0),
const Offset(68.0, -49.0),
const Offset(-24.0, -49.0),
],
excludes: <Offset>[
const Offset(98.0, -32.0), // inside full size, outside small
const Offset(-16.0, -32.0), // inside full size, outside small
const Offset(-40.0, -32.0), // inside full size, outside small
const Offset(90.1, -49.0),
const Offset(-24.1, -49.0),
const Offset(-40.1, -49.0),
],
),
);
......@@ -436,10 +411,9 @@ void main() {
color: sliderTheme.valueIndicatorColor,
includes: <Offset>[
const Offset(0.0, -38.8),
const Offset(98.0, -38.8),
const Offset(-16.0, -38.8),
const Offset(10.0, -23.0), // Inside large, outside scale=1.0
const Offset(-4.0, -23.0), // Inside large, outside scale=1.0
const Offset(92.0, -38.8),
const Offset(8.0, -23.0), // Inside large, outside scale=1.0
const Offset(-2.0, -23.0), // Inside large, outside scale=1.0
],
excludes: <Offset>[
const Offset(98.5, -38.8),
......@@ -461,8 +435,8 @@ void main() {
expect(
sliderBox,
paints
..rect(rect: Rect.fromLTRB(16.0, 292.0, 208.0, 308.0), color: sliderTheme.activeTrackColor)
..rect(rect: Rect.fromLTRB(208.0, 292.0, 784.0, 308.0), color: sliderTheme.inactiveTrackColor),
..rect(rect: Rect.fromLTRB(32.0, 292.0, 202.0, 308.0), color: sliderTheme.activeTrackColor)
..rect(rect: Rect.fromLTRB(222.0, 292.0, 776.0, 308.0), color: sliderTheme.inactiveTrackColor),
);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, enabled: false));
......@@ -473,8 +447,8 @@ void main() {
expect(
sliderBox,
paints
..rect(rect: Rect.fromLTRB(16.0, 292.0, 202.0, 308.0), color: sliderTheme.disabledActiveTrackColor)
..rect(rect: Rect.fromLTRB(214.0, 292.0, 784.0, 308.0), color: sliderTheme.disabledInactiveTrackColor),
..rect(rect: Rect.fromLTRB(32.0, 292.0, 202.0, 308.0), color: sliderTheme.disabledActiveTrackColor)
..rect(rect: Rect.fromLTRB(222.0, 292.0, 776.0, 308.0), color: sliderTheme.disabledInactiveTrackColor),
);
});
......@@ -491,7 +465,7 @@ void main() {
expect(
sliderBox,
paints..circle(x: 208, y: 300, radius: 7, color: sliderTheme.thumbColor),
paints..circle(x: 212, y: 300, radius: 7, color: sliderTheme.thumbColor),
);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, enabled: false));
......@@ -499,7 +473,7 @@ void main() {
expect(
sliderBox,
paints..circle(x: 208, y: 300, radius: 11, color: sliderTheme.disabledThumbColor),
paints..circle(x: 212, y: 300, radius: 11, color: sliderTheme.disabledThumbColor),
);
});
......@@ -515,26 +489,21 @@ void main() {
expect(
sliderBox,
paints..circle(x: 208, y: 300, radius: 9, color: sliderTheme.thumbColor),
paints..circle(x: 212, y: 300, radius: 9, color: sliderTheme.thumbColor),
);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.25, enabled: false));
await tester.pumpAndSettle(); // wait for disable animation
// Radius should be 6, or 2/3 of 9. 2/3 because the default disabled thumb
// radius is 4 and the default enabled thumb radius is 6.
// TODO(clocksmith): This ratio will change once thumb sizes are updated to spec.
expect(
sliderBox,
paints..circle(x: 208, y: 300, radius: 6, color: sliderTheme.disabledThumbColor),
paints..circle(x: 212, y: 300, radius: 9, color: sliderTheme.disabledThumbColor),
);
});
testWidgets('The default slider tick mark shape size can be overridden', (WidgetTester tester) async {
final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith(
tickMarkShape: const RoundSliderTickMarkShape(
tickMarkRadius: 5
),
tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 5),
activeTickMarkColor: const Color(0xfadedead),
inactiveTickMarkColor: const Color(0xfadebeef),
disabledActiveTickMarkColor: const Color(0xfadecafe),
......@@ -548,9 +517,9 @@ void main() {
expect(
sliderBox,
paints
..circle(x: 21, y: 300, radius: 5, color: sliderTheme.activeTickMarkColor)
..circle(x: 29, y: 300, radius: 5, color: sliderTheme.activeTickMarkColor)
..circle(x: 400, y: 300, radius: 5, color: sliderTheme.activeTickMarkColor)
..circle(x: 779, y: 300, radius: 5, color: sliderTheme.inactiveTickMarkColor),
..circle(x: 771, y: 300, radius: 5, color: sliderTheme.inactiveTickMarkColor),
);
await tester.pumpWidget(_buildApp(sliderTheme, value: 0.5, divisions: 2, enabled: false));
......@@ -559,9 +528,9 @@ void main() {
expect(
sliderBox,
paints
..circle(x: 21, y: 300, radius: 5, color: sliderTheme.disabledActiveTickMarkColor)
..circle(x: 29, y: 300, radius: 5, color: sliderTheme.disabledActiveTickMarkColor)
..circle(x: 400, y: 300, radius: 5, color: sliderTheme.disabledActiveTickMarkColor)
..circle(x: 779, y: 300, radius: 5, color: sliderTheme.disabledInactiveTickMarkColor),
..circle(x: 771, y: 300, radius: 5, color: sliderTheme.disabledInactiveTickMarkColor),
);
});
......
......@@ -56,16 +56,6 @@ void main() {
expect(darkTheme.accentTextTheme.title.color, typography.white.title.color);
});
test('Default slider indicator style gets a default body2 if accentTextTheme.body2 is null', () {
const TextTheme noBody2TextTheme = TextTheme(body2: null);
final ThemeData lightTheme = ThemeData(brightness: Brightness.light, accentTextTheme: noBody2TextTheme);
final ThemeData darkTheme = ThemeData(brightness: Brightness.dark, accentTextTheme: noBody2TextTheme);
final Typography typography = Typography(platform: lightTheme.platform);
expect(lightTheme.sliderTheme.valueIndicatorTextStyle, equals(typography.white.body2));
expect(darkTheme.sliderTheme.valueIndicatorTextStyle, equals(typography.black.body2));
});
test('Default chip label style gets a default body2 if textTheme.body2 is null', () {
const TextTheme noBody2TextTheme = TextTheme(body2: null);
final ThemeData lightTheme = ThemeData(brightness: Brightness.light, textTheme: noBody2TextTheme);
......
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