diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index 213884cdd7..5cc935716c 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -64,6 +64,7 @@ class Slider extends StatefulWidget { this.divisions, this.label, this.activeColor, + this.inactiveColor, this.thumbOpenAtMin: false, }) : assert(value != null), assert(min != null), @@ -138,6 +139,11 @@ class Slider extends StatefulWidget { /// Defaults to accent color of the current [Theme]. final Color activeColor; + /// The color for the unselected portion of the slider. + /// + /// Defaults to the unselected widget color of the current [Theme]. + final Color inactiveColor; + /// Whether the thumb should be an open circle when the slider is at its minimum position. /// /// When this property is false, the thumb does not change when it the slider @@ -178,6 +184,7 @@ class _SliderState extends State with TickerProviderStateMixin { divisions: widget.divisions, label: widget.label, activeColor: widget.activeColor ?? theme.accentColor, + inactiveColor: widget.inactiveColor ?? theme.unselectedWidgetColor, thumbOpenAtMin: widget.thumbOpenAtMin, textTheme: theme.accentTextTheme, onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null, @@ -193,6 +200,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { this.divisions, this.label, this.activeColor, + this.inactiveColor, this.thumbOpenAtMin, this.textTheme, this.onChanged, @@ -203,6 +211,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { final int divisions; final String label; final Color activeColor; + final Color inactiveColor; final bool thumbOpenAtMin; final TextTheme textTheme; final ValueChanged onChanged; @@ -215,6 +224,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { divisions: divisions, label: label, activeColor: activeColor, + inactiveColor: inactiveColor, thumbOpenAtMin: thumbOpenAtMin, textTheme: textTheme, onChanged: onChanged, @@ -229,6 +239,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { ..divisions = divisions ..label = label ..activeColor = activeColor + ..inactiveColor = inactiveColor ..thumbOpenAtMin = thumbOpenAtMin ..textTheme = textTheme ..onChanged = onChanged; @@ -246,11 +257,9 @@ const double _kMinimumTrackWidth = _kActiveThumbRadius; // biggest of the thumb const double _kPreferredTotalWidth = _kPreferredTrackWidth + 2 * _kReactionRadius; const double _kMinimumTotalWidth = _kMinimumTrackWidth + 2 * _kReactionRadius; -final Color _kInactiveTrackColor = Colors.grey.shade400; final Color _kActiveTrackColor = Colors.grey; final Tween _kReactionRadiusTween = new Tween(begin: _kThumbRadius, end: _kReactionRadius); final Tween _kThumbRadiusTween = new Tween(begin: _kThumbRadius, end: _kActiveThumbRadius); -final ColorTween _kTrackColorTween = new ColorTween(begin: _kInactiveTrackColor, end: _kActiveTrackColor); final ColorTween _kTickColorTween = new ColorTween(begin: Colors.transparent, end: Colors.black54); final Duration _kDiscreteTransitionDuration = const Duration(milliseconds: 500); @@ -276,6 +285,7 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { int divisions, String label, Color activeColor, + Color inactiveColor, bool thumbOpenAtMin, TextTheme textTheme, this.onChanged, @@ -284,6 +294,7 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { _value = value, _divisions = divisions, _activeColor = activeColor, + _inactiveColor = inactiveColor, _thumbOpenAtMin = thumbOpenAtMin, _textTheme = textTheme { this.label = label; @@ -363,6 +374,15 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { markNeedsPaint(); } + Color get inactiveColor => _inactiveColor; + Color _inactiveColor; + set inactiveColor(Color value) { + if (value == _inactiveColor) + return; + _inactiveColor = value; + markNeedsPaint(); + } + bool get thumbOpenAtMin => _thumbOpenAtMin; bool _thumbOpenAtMin; set thumbOpenAtMin(bool value) { @@ -451,7 +471,6 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { } } - @override double computeMinIntrinsicWidth(double height) { return _kMinimumTotalWidth; @@ -501,8 +520,8 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { final double trackRight = trackLeft + trackLength; final double trackActive = trackLeft + trackLength * value; - final Paint primaryPaint = new Paint()..color = enabled ? _activeColor : _kInactiveTrackColor; - final Paint trackPaint = new Paint()..color = _kTrackColorTween.evaluate(_reaction); + final Paint primaryPaint = new Paint()..color = enabled ? _activeColor : _inactiveColor; + final Paint trackPaint = new Paint()..color = _inactiveColor; final Offset thumbCenter = new Offset(trackActive, trackCenter); final double thumbRadius = enabled ? _kThumbRadiusTween.evaluate(_reaction) : _kDisabledThumbRadius; diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index 3942e40395..05f876bc20 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -118,6 +118,72 @@ void main() { log.clear(); }); + testWidgets('Slider has a customizable active color', + (WidgetTester tester) async { + final Color customColor = const Color(0xFF4CD964); + final ThemeData theme = new ThemeData(platform: TargetPlatform.android); + Widget buildApp(Color activeColor) { + return new Material( + child: new Center( + child: new Theme( + data: theme, + child: new Slider( + value: 0.5, + activeColor: activeColor, + onChanged: (double newValue) {}, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildApp(null)); + + final RenderBox sliderBox = + tester.firstRenderObject(find.byType(Slider)); + + expect(sliderBox, paints..rect(color: theme.accentColor)..rect(color: theme.unselectedWidgetColor)); + expect(sliderBox, paints..circle(color: theme.accentColor)); + expect(sliderBox, isNot(paints..circle(color: customColor))); + expect(sliderBox, isNot(paints..circle(color: theme.unselectedWidgetColor))); + await tester.pumpWidget(buildApp(customColor)); + expect(sliderBox, paints..rect(color: customColor)..rect(color: theme.unselectedWidgetColor)); + expect(sliderBox, paints..circle(color: customColor)); + expect(sliderBox, isNot(paints..circle(color: theme.accentColor))); + expect(sliderBox, isNot(paints..circle(color: theme.unselectedWidgetColor))); + }); + + testWidgets('Slider has a customizable inactive color', + (WidgetTester tester) async { + final Color customColor = const Color(0xFF4CD964); + final ThemeData theme = new ThemeData(platform: TargetPlatform.android); + Widget buildApp(Color inactiveColor) { + return new Material( + child: new Center( + child: new Theme( + data: theme, + child: new Slider( + value: 0.5, + inactiveColor: inactiveColor, + onChanged: (double newValue) {}, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildApp(null)); + + final RenderBox sliderBox = + tester.firstRenderObject(find.byType(Slider)); + + expect(sliderBox, paints..rect(color: theme.accentColor)..rect(color: theme.unselectedWidgetColor)); + expect(sliderBox, paints..circle(color: theme.accentColor)); + await tester.pumpWidget(buildApp(customColor)); + expect(sliderBox, paints..rect(color: theme.accentColor)..rect(color: customColor)); + expect(sliderBox, paints..circle(color: theme.accentColor)); + }); + testWidgets('Slider can draw an open thumb at min', (WidgetTester tester) async { Widget buildApp(bool thumbOpenAtMin) {