diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index 32da622ab5c..03bbea45b96 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -428,27 +428,52 @@ class _SliderState extends State 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 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, diff --git a/packages/flutter/lib/src/material/slider_theme.dart b/packages/flutter/lib/src/material/slider_theme.dart index 205b5d3a378..73357da6302 100644 --- a/packages/flutter/lib/src/material/slider_theme.dart +++ b/packages/flutter/lib/src/material/slider_theme.dart @@ -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 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 enableAnimation, - TextDirection textDirection, - Offset thumbCenter, - bool isDiscrete, - bool isEnabled, + @required RenderBox parentBox, + @required SliderThemeData sliderTheme, + @required Animation 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 enableAnimation, - TextDirection textDirection, - Offset thumbCenter, - bool isEnabled, + @required RenderBox parentBox, + @required SliderThemeData sliderTheme, + @required Animation 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 activationAnimation, - Animation enableAnimation, - bool isDiscrete, - TextPainter labelPainter, - RenderBox parentBox, - SliderThemeData sliderTheme, - TextDirection textDirection, - double value, + @required Animation activationAnimation, + @required Animation 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 radiusTween = Tween( 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 activationAnimation, - Animation enableAnimation, - bool isDiscrete, - TextPainter labelPainter, - RenderBox parentBox, - SliderThemeData sliderTheme, - TextDirection textDirection, - double value, + @required Animation activationAnimation, + @required Animation 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 radiusTween = Tween( 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 activationAnimation, - Animation enableAnimation, - bool isDiscrete, - TextPainter labelPainter, - RenderBox parentBox, - SliderThemeData sliderTheme, - TextDirection textDirection, - double value, + @required Animation activationAnimation, + @required Animation 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, diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index d1db506b197..e124d316b9a 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -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(); diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index e10459b2e2f..8f7c092b6d0 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -298,8 +298,8 @@ void main() { ); final List expectedLog = [ - 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 expectedLog = [ - 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(find.byType(Slider)).size, const Size(144.0 + 2.0 * 16.0, 600.0)); + expect(tester.renderObject(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(find.byType(Slider)).size, const Size(144.0 + 2.0 * 16.0, 32.0)); + expect(tester.renderObject(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), ); } diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index a3ff5e8207f..58e2178fcfc 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -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())); - expect(sliderTheme.tickMarkShape, equals(isInstanceOf())); - expect(sliderTheme.thumbShape, equals(isInstanceOf())); - expect(sliderTheme.valueIndicatorShape, equals(isInstanceOf())); - expect(sliderTheme.overlayShape, equals(isInstanceOf())); - }); - - 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(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: [ 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: [const Offset(98.1, -40.0), const Offset(-16.1, -40.0)], + excludes: [const Offset(98.1, -40.0), const Offset(-20.1, -40.0)], ), ); await gesture.up(); @@ -390,9 +365,9 @@ void main() { includes: [ 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: [const Offset(16.1, -40.0), const Offset(-98.1, -40.0)], + excludes: [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: [ 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: [ 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: [ 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: [ 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), ); }); diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart index c56c6e1d61a..d191ff434bc 100644 --- a/packages/flutter/test/material/theme_data_test.dart +++ b/packages/flutter/test/material/theme_data_test.dart @@ -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);