Unverified Commit 701eff4a authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Slider Visual Update (#14901)

This implements an update to the look of the Slider widget.

Specifically, it does the following:

* Adds the ability to customize the colors of all components of the slider
* Adds the ability to customize the shape of the slider thumb and value indicator
* Adds the ability to show the value indicator on continuous sliders
* Updates the default value indicator to be a "paddle" shape with new animations.
* Changes the tick marks to be visible all the time on discrete sliders
* Fixes a memory leak of an animation controller.
* Removes "thumbOpenAtMin" flag, which is no longer needed, and can be emulated by the
custom thumb shape support. It was not widely used.
* Adds tests for all of the new features.
parent d2dcec22
...@@ -31,7 +31,6 @@ class _SliderDemoState extends State<SliderDemo> { ...@@ -31,7 +31,6 @@ class _SliderDemoState extends State<SliderDemo> {
value: _value, value: _value,
min: 0.0, min: 0.0,
max: 100.0, max: 100.0,
thumbOpenAtMin: true,
onChanged: (double value) { onChanged: (double value) {
setState(() { setState(() {
_value = value; _value = value;
...@@ -44,7 +43,7 @@ class _SliderDemoState extends State<SliderDemo> { ...@@ -44,7 +43,7 @@ class _SliderDemoState extends State<SliderDemo> {
new Column( new Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: const <Widget> [ children: const <Widget> [
const Slider(value: 0.25, thumbOpenAtMin: true, onChanged: null), const Slider(value: 0.25, onChanged: null),
const Text('Disabled'), const Text('Disabled'),
] ]
), ),
...@@ -57,7 +56,6 @@ class _SliderDemoState extends State<SliderDemo> { ...@@ -57,7 +56,6 @@ class _SliderDemoState extends State<SliderDemo> {
max: 100.0, max: 100.0,
divisions: 5, divisions: 5,
label: '${_discreteValue.round()}', label: '${_discreteValue.round()}',
thumbOpenAtMin: true,
onChanged: (double value) { onChanged: (double value) {
setState(() { setState(() {
_discreteValue = value; _discreteValue = value;
......
...@@ -77,6 +77,7 @@ export 'src/material/scaffold.dart'; ...@@ -77,6 +77,7 @@ export 'src/material/scaffold.dart';
export 'src/material/scrollbar.dart'; export 'src/material/scrollbar.dart';
export 'src/material/shadows.dart'; export 'src/material/shadows.dart';
export 'src/material/slider.dart'; export 'src/material/slider.dart';
export 'src/material/slider_theme.dart';
export 'src/material/snack_bar.dart'; export 'src/material/snack_bar.dart';
export 'src/material/stepper.dart'; export 'src/material/stepper.dart';
export 'src/material/switch.dart'; export 'src/material/switch.dart';
......
...@@ -135,7 +135,7 @@ class ButtonTheme extends InheritedWidget { ...@@ -135,7 +135,7 @@ class ButtonTheme extends InheritedWidget {
/// A button theme can be specified as part of the overall Material theme /// A button theme can be specified as part of the overall Material theme
/// using [ThemeData.buttomTheme]. The Material theme's button theme data /// using [ThemeData.buttomTheme]. The Material theme's button theme data
/// can be overridden with [ButtonTheme]. /// can be overridden with [ButtonTheme].
class ButtonThemeData { class ButtonThemeData extends Diagnosticable {
/// Create a button theme object that can be used with [ButtonTheme] /// Create a button theme object that can be used with [ButtonTheme]
/// or [ThemeData]. /// or [ThemeData].
/// ///
...@@ -251,4 +251,18 @@ class ButtonThemeData { ...@@ -251,4 +251,18 @@ class ButtonThemeData {
shape, shape,
); );
} }
@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
final ButtonThemeData defaultTheme = const ButtonThemeData();
description.add(new EnumProperty<ButtonTextTheme>('textTheme', textTheme,
defaultValue: defaultTheme.textTheme));
description.add(new DoubleProperty('minWidth', minWidth, defaultValue: defaultTheme.minWidth));
description.add(new DoubleProperty('height', height, defaultValue: defaultTheme.height));
description.add(new DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding,
defaultValue: defaultTheme.padding));
description.add(
new DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: defaultTheme.shape));
}
} }
...@@ -312,7 +312,7 @@ class InkResponse extends StatefulWidget { ...@@ -312,7 +312,7 @@ class InkResponse extends StatefulWidget {
/// * [highlightColor], the color of the highlight. /// * [highlightColor], the color of the highlight.
/// * [InkSplash.splashFactory], which defines the default splash. /// * [InkSplash.splashFactory], which defines the default splash.
/// * [InkRipple.splashFactory], which defines a splash that spreads out /// * [InkRipple.splashFactory], which defines a splash that spreads out
/// more aggresively than the default. /// more aggressively than the default.
final InteractiveInkFeatureFactory splashFactory; final InteractiveInkFeatureFactory splashFactory;
/// Whether detected gestures should provide acoustic and/or haptic feedback. /// Whether detected gestures should provide acoustic and/or haptic feedback.
......
...@@ -53,7 +53,7 @@ class _InputBorderGap extends ChangeNotifier { ...@@ -53,7 +53,7 @@ class _InputBorderGap extends ChangeNotifier {
// Used to interpolate between two InputBorders. // Used to interpolate between two InputBorders.
class _InputBorderTween extends Tween<InputBorder> { class _InputBorderTween extends Tween<InputBorder> {
_InputBorderTween({ InputBorder begin, InputBorder end }) : super(begin: begin, end: end); _InputBorderTween({InputBorder begin, InputBorder end}) : super(begin: begin, end: end);
@override @override
InputBorder lerp(double t) => ShapeBorder.lerp(begin, end, t); InputBorder lerp(double t) => ShapeBorder.lerp(begin, end, t);
...@@ -108,7 +108,7 @@ class _BorderContainer extends StatefulWidget { ...@@ -108,7 +108,7 @@ class _BorderContainer extends StatefulWidget {
@required this.border, @required this.border,
@required this.gap, @required this.gap,
@required this.gapAnimation, @required this.gapAnimation,
this.child this.child,
}) : assert(border != null), }) : assert(border != null),
assert(gap != null), assert(gap != null),
super(key: key); super(key: key);
...@@ -2164,7 +2164,7 @@ class InputDecoration { ...@@ -2164,7 +2164,7 @@ class InputDecoration {
/// The [InputDecoration.applyDefaults] method is used to combine a input /// The [InputDecoration.applyDefaults] method is used to combine a input
/// decoration theme with an [InputDecoration] object. /// decoration theme with an [InputDecoration] object.
@immutable @immutable
class InputDecorationTheme { class InputDecorationTheme extends Diagnosticable {
/// Creates a value for [ThemeData.inputDecorationTheme] that /// Creates a value for [ThemeData.inputDecorationTheme] that
/// defines default values for [InputDecorator]. /// defines default values for [InputDecorator].
/// ///
...@@ -2300,4 +2300,36 @@ class InputDecorationTheme { ...@@ -2300,4 +2300,36 @@ class InputDecorationTheme {
/// * [OutlineInputBorder], an [InputDecorator] border which draws a /// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container. /// rounded rectangle around the input decorator's container.
final InputBorder border; final InputBorder border;
@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
final InputDecorationTheme defaultTheme = const InputDecorationTheme();
description.add(new DiagnosticsProperty<TextStyle>('labelStyle', labelStyle,
defaultValue: defaultTheme.labelStyle));
description.add(new DiagnosticsProperty<TextStyle>('helperStyle', helperStyle,
defaultValue: defaultTheme.helperStyle));
description.add(new DiagnosticsProperty<TextStyle>('hintStyle', hintStyle,
defaultValue: defaultTheme.hintStyle));
description.add(new DiagnosticsProperty<TextStyle>('errorStyle', errorStyle,
defaultValue: defaultTheme.errorStyle));
description
.add(new DiagnosticsProperty<bool>('isDense', isDense, defaultValue: defaultTheme.isDense));
description.add(new DiagnosticsProperty<EdgeInsets>('contentPadding', contentPadding,
defaultValue: defaultTheme.contentPadding));
description.add(new DiagnosticsProperty<bool>('isCollapsed', isCollapsed,
defaultValue: defaultTheme.isCollapsed));
description.add(new DiagnosticsProperty<TextStyle>('prefixStyle', prefixStyle,
defaultValue: defaultTheme.prefixStyle));
description.add(new DiagnosticsProperty<TextStyle>('suffixStyle', suffixStyle,
defaultValue: defaultTheme.suffixStyle));
description.add(new DiagnosticsProperty<TextStyle>('counterStyle', counterStyle,
defaultValue: defaultTheme.counterStyle));
description
.add(new DiagnosticsProperty<bool>('filled', filled, defaultValue: defaultTheme.filled));
description.add(new DiagnosticsProperty<Color>('fillColor', fillColor,
defaultValue: defaultTheme.fillColor));
description.add(
new DiagnosticsProperty<InputBorder>('border', border, defaultValue: defaultTheme.border));
}
} }
This diff is collapsed.
...@@ -33,7 +33,7 @@ import 'colors.dart'; ...@@ -33,7 +33,7 @@ import 'colors.dart';
/// globally adjusted, such as the color scheme. /// globally adjusted, such as the color scheme.
/// * <http://material.google.com/style/typography.html> /// * <http://material.google.com/style/typography.html>
@immutable @immutable
class TextTheme { class TextTheme extends Diagnosticable {
/// Creates a text theme that uses the given values. /// Creates a text theme that uses the given values.
/// ///
/// Rather than creating a new text theme, consider using [Typography.black] /// Rather than creating a new text theme, consider using [Typography.black]
...@@ -114,7 +114,7 @@ class TextTheme { ...@@ -114,7 +114,7 @@ class TextTheme {
TextStyle body2, TextStyle body2,
TextStyle body1, TextStyle body1,
TextStyle caption, TextStyle caption,
TextStyle button TextStyle button,
}) { }) {
return new TextTheme( return new TextTheme(
display4: display4 ?? this.display4, display4: display4 ?? this.display4,
...@@ -353,6 +353,34 @@ class TextTheme { ...@@ -353,6 +353,34 @@ class TextTheme {
button, button,
); );
} }
@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
final TextTheme defaultTheme = new Typography(platform: defaultTargetPlatform).black;
description.add(new DiagnosticsProperty<TextStyle>('display4', display4,
defaultValue: defaultTheme.display4));
description.add(new DiagnosticsProperty<TextStyle>('display3', display3,
defaultValue: defaultTheme.display3));
description.add(new DiagnosticsProperty<TextStyle>('display2', display2,
defaultValue: defaultTheme.display2));
description.add(new DiagnosticsProperty<TextStyle>('display1', display1,
defaultValue: defaultTheme.display1));
description.add(new DiagnosticsProperty<TextStyle>('headline', headline,
defaultValue: defaultTheme.headline));
description
.add(new DiagnosticsProperty<TextStyle>('title', title, defaultValue: defaultTheme.title));
description.add(
new DiagnosticsProperty<TextStyle>('subhead', subhead, defaultValue: defaultTheme.subhead));
description
.add(new DiagnosticsProperty<TextStyle>('body2', body2, defaultValue: defaultTheme.body2));
description
.add(new DiagnosticsProperty<TextStyle>('body1', body1, defaultValue: defaultTheme.body1));
description.add(
new DiagnosticsProperty<TextStyle>('caption', caption, defaultValue: defaultTheme.caption));
description.add(
new DiagnosticsProperty<TextStyle>('button', button, defaultValue: defaultTheme.button));
}
} }
/// The two material design text themes. /// The two material design text themes.
...@@ -373,7 +401,7 @@ class TextTheme { ...@@ -373,7 +401,7 @@ class TextTheme {
/// * <http://material.google.com/style/typography.html> /// * <http://material.google.com/style/typography.html>
class Typography { class Typography {
/// Creates the default typography for the specified platform. /// Creates the default typography for the specified platform.
factory Typography({ @required TargetPlatform platform }) { factory Typography({@required TargetPlatform platform}) {
assert(platform != null); assert(platform != null);
switch (platform) { switch (platform) {
case TargetPlatform.android: case TargetPlatform.android:
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
import 'dart:ui' show Color, hashValues; import 'dart:ui' show Color, hashValues;
import 'dart:ui' as ui show lerpDouble; import 'dart:ui' as ui show lerpDouble;
import 'package:flutter/foundation.dart';
/// Defines the color, opacity, and size of icons. /// Defines the color, opacity, and size of icons.
/// ///
/// Used by [IconTheme] to control the color, opacity, and size of icons in a /// Used by [IconTheme] to control the color, opacity, and size of icons in a
...@@ -13,29 +15,26 @@ import 'dart:ui' as ui show lerpDouble; ...@@ -13,29 +15,26 @@ import 'dart:ui' as ui show lerpDouble;
/// To obtain the current icon theme, use [IconTheme.of]. To convert an icon /// To obtain the current icon theme, use [IconTheme.of]. To convert an icon
/// theme to a version with all the fields filled in, use [new /// theme to a version with all the fields filled in, use [new
/// IconThemeData.fallback]. /// IconThemeData.fallback].
class IconThemeData { class IconThemeData extends Diagnosticable {
/// Creates an icon theme data. /// Creates an icon theme data.
/// ///
/// The opacity applies to both explicit and default icon colors. The value /// The opacity applies to both explicit and default icon colors. The value
/// is clamped between 0.0 and 1.0. /// is clamped between 0.0 and 1.0.
const IconThemeData({ this.color, double opacity, this.size }) : _opacity = opacity; const IconThemeData({this.color, double opacity, this.size}) : _opacity = opacity;
/// Creates an icon them with some reasonable default values. /// Creates an icon them with some reasonable default values.
/// ///
/// The [color] is black, the [opacity] is 1.0, and the [size] is 24.0. /// The [color] is black, the [opacity] is 1.0, and the [size] is 24.0.
const IconThemeData.fallback() const IconThemeData.fallback()
: color = const Color(0xFF000000), : color = const Color(0xFF000000),
_opacity = 1.0, _opacity = 1.0,
size = 24.0; size = 24.0;
/// Creates a copy of this icon theme but with the given fields replaced with /// Creates a copy of this icon theme but with the given fields replaced with
/// the new values. /// the new values.
IconThemeData copyWith({ Color color, double opacity, double size }) { IconThemeData copyWith({Color color, double opacity, double size}) {
return new IconThemeData( return new IconThemeData(
color: color ?? this.color, color: color ?? this.color, opacity: opacity ?? this.opacity, size: size ?? this.size);
opacity: opacity ?? this.opacity,
size: size ?? this.size
);
} }
/// Returns a new icon theme that matches this icon theme but with some values /// Returns a new icon theme that matches this icon theme but with some values
...@@ -44,11 +43,7 @@ class IconThemeData { ...@@ -44,11 +43,7 @@ class IconThemeData {
IconThemeData merge(IconThemeData other) { IconThemeData merge(IconThemeData other) {
if (other == null) if (other == null)
return this; return this;
return copyWith( return copyWith(color: other.color, opacity: other.opacity, size: other.size);
color: other.color,
opacity: other.opacity,
size: other.size
);
} }
/// Whether all the properties of this object are non-null. /// Whether all the properties of this object are non-null.
...@@ -100,16 +95,13 @@ class IconThemeData { ...@@ -100,16 +95,13 @@ class IconThemeData {
int get hashCode => hashValues(color, opacity, size); int get hashCode => hashValues(color, opacity, size);
@override @override
String toString() { void debugFillProperties(DiagnosticPropertiesBuilder description) {
final List<String> result = <String>[]; super.debugFillProperties(description);
if (color != null) if (color == null && _opacity == null && size == null) {
result.add('color: $color'); return;
if (_opacity != null) }
result.add('opacity: $_opacity'); description.add(new DiagnosticsProperty<Color>('color', color));
if (size != null) description.add(new DoubleProperty('opacity', _opacity));
result.add('size: $size'); description.add(new DoubleProperty('size', size));
if (result.isEmpty)
return '<no theme>';
return result.join(', ');
} }
} }
This diff is collapsed.
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