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> {
value: _value,
min: 0.0,
max: 100.0,
thumbOpenAtMin: true,
onChanged: (double value) {
setState(() {
_value = value;
......@@ -44,7 +43,7 @@ class _SliderDemoState extends State<SliderDemo> {
new Column(
mainAxisSize: MainAxisSize.min,
children: const <Widget> [
const Slider(value: 0.25, thumbOpenAtMin: true, onChanged: null),
const Slider(value: 0.25, onChanged: null),
const Text('Disabled'),
]
),
......@@ -57,7 +56,6 @@ class _SliderDemoState extends State<SliderDemo> {
max: 100.0,
divisions: 5,
label: '${_discreteValue.round()}',
thumbOpenAtMin: true,
onChanged: (double value) {
setState(() {
_discreteValue = value;
......
......@@ -77,6 +77,7 @@ export 'src/material/scaffold.dart';
export 'src/material/scrollbar.dart';
export 'src/material/shadows.dart';
export 'src/material/slider.dart';
export 'src/material/slider_theme.dart';
export 'src/material/snack_bar.dart';
export 'src/material/stepper.dart';
export 'src/material/switch.dart';
......
......@@ -135,7 +135,7 @@ class ButtonTheme extends InheritedWidget {
/// A button theme can be specified as part of the overall Material theme
/// using [ThemeData.buttomTheme]. The Material theme's button theme data
/// can be overridden with [ButtonTheme].
class ButtonThemeData {
class ButtonThemeData extends Diagnosticable {
/// Create a button theme object that can be used with [ButtonTheme]
/// or [ThemeData].
///
......@@ -251,4 +251,18 @@ class ButtonThemeData {
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 {
/// * [highlightColor], the color of the highlight.
/// * [InkSplash.splashFactory], which defines the default splash.
/// * [InkRipple.splashFactory], which defines a splash that spreads out
/// more aggresively than the default.
/// more aggressively than the default.
final InteractiveInkFeatureFactory splashFactory;
/// Whether detected gestures should provide acoustic and/or haptic feedback.
......
......@@ -53,7 +53,7 @@ class _InputBorderGap extends ChangeNotifier {
// Used to interpolate between two InputBorders.
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
InputBorder lerp(double t) => ShapeBorder.lerp(begin, end, t);
......@@ -108,7 +108,7 @@ class _BorderContainer extends StatefulWidget {
@required this.border,
@required this.gap,
@required this.gapAnimation,
this.child
this.child,
}) : assert(border != null),
assert(gap != null),
super(key: key);
......@@ -2164,7 +2164,7 @@ class InputDecoration {
/// The [InputDecoration.applyDefaults] method is used to combine a input
/// decoration theme with an [InputDecoration] object.
@immutable
class InputDecorationTheme {
class InputDecorationTheme extends Diagnosticable {
/// Creates a value for [ThemeData.inputDecorationTheme] that
/// defines default values for [InputDecorator].
///
......@@ -2300,4 +2300,36 @@ class InputDecorationTheme {
/// * [OutlineInputBorder], an [InputDecorator] border which draws a
/// rounded rectangle around the input decorator's container.
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';
/// globally adjusted, such as the color scheme.
/// * <http://material.google.com/style/typography.html>
@immutable
class TextTheme {
class TextTheme extends Diagnosticable {
/// Creates a text theme that uses the given values.
///
/// Rather than creating a new text theme, consider using [Typography.black]
......@@ -114,7 +114,7 @@ class TextTheme {
TextStyle body2,
TextStyle body1,
TextStyle caption,
TextStyle button
TextStyle button,
}) {
return new TextTheme(
display4: display4 ?? this.display4,
......@@ -353,6 +353,34 @@ class TextTheme {
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.
......@@ -373,7 +401,7 @@ class TextTheme {
/// * <http://material.google.com/style/typography.html>
class Typography {
/// Creates the default typography for the specified platform.
factory Typography({ @required TargetPlatform platform }) {
factory Typography({@required TargetPlatform platform}) {
assert(platform != null);
switch (platform) {
case TargetPlatform.android:
......
......@@ -5,6 +5,8 @@
import 'dart:ui' show Color, hashValues;
import 'dart:ui' as ui show lerpDouble;
import 'package:flutter/foundation.dart';
/// Defines the color, opacity, and size of icons.
///
/// 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;
/// 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
/// IconThemeData.fallback].
class IconThemeData {
class IconThemeData extends Diagnosticable {
/// Creates an icon theme data.
///
/// The opacity applies to both explicit and default icon colors. The value
/// 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.
///
/// The [color] is black, the [opacity] is 1.0, and the [size] is 24.0.
const IconThemeData.fallback()
: color = const Color(0xFF000000),
_opacity = 1.0,
size = 24.0;
: color = const Color(0xFF000000),
_opacity = 1.0,
size = 24.0;
/// Creates a copy of this icon theme but with the given fields replaced with
/// the new values.
IconThemeData copyWith({ Color color, double opacity, double size }) {
IconThemeData copyWith({Color color, double opacity, double size}) {
return new IconThemeData(
color: color ?? this.color,
opacity: opacity ?? this.opacity,
size: size ?? this.size
);
color: color ?? this.color, opacity: opacity ?? this.opacity, size: size ?? this.size);
}
/// Returns a new icon theme that matches this icon theme but with some values
......@@ -44,11 +43,7 @@ class IconThemeData {
IconThemeData merge(IconThemeData other) {
if (other == null)
return this;
return copyWith(
color: other.color,
opacity: other.opacity,
size: other.size
);
return copyWith(color: other.color, opacity: other.opacity, size: other.size);
}
/// Whether all the properties of this object are non-null.
......@@ -100,16 +95,13 @@ class IconThemeData {
int get hashCode => hashValues(color, opacity, size);
@override
String toString() {
final List<String> result = <String>[];
if (color != null)
result.add('color: $color');
if (_opacity != null)
result.add('opacity: $_opacity');
if (size != null)
result.add('size: $size');
if (result.isEmpty)
return '<no theme>';
return result.join(', ');
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
if (color == null && _opacity == null && size == null) {
return;
}
description.add(new DiagnosticsProperty<Color>('color', color));
description.add(new DoubleProperty('opacity', _opacity));
description.add(new DoubleProperty('size', size));
}
}
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