Unverified Commit 10fe2056 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Add a slider demo, and a text theme for SliderThemeData (#15620)

This adds a slider demo with a custom theme to the gallery.

In the process of adding this, I decided to add a text theme to the SliderThemeData, since it's a pain to change the text style on the value indicator otherwise.
parent 7a285301
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:math' as math;
import 'package:flutter/material.dart';
class SliderDemo extends StatefulWidget {
......@@ -11,12 +13,124 @@ class SliderDemo extends StatefulWidget {
_SliderDemoState createState() => new _SliderDemoState();
}
Path _triangle(double size, Offset thumbCenter, {bool invert: false}) {
final Path thumbPath = new Path();
final double height = math.sqrt(3.0) / 2.0;
final double halfSide = size / 2.0;
final double centerHeight = size * height / 3.0;
final double sign = invert ? -1.0 : 1.0;
thumbPath.moveTo(thumbCenter.dx - halfSide, thumbCenter.dy + sign * centerHeight);
thumbPath.lineTo(thumbCenter.dx, thumbCenter.dy - 2.0 * sign * centerHeight);
thumbPath.lineTo(thumbCenter.dx + halfSide, thumbCenter.dy + sign * centerHeight);
thumbPath.close();
return thumbPath;
}
class _CustomThumbShape extends SliderComponentShape {
static const double _thumbSize = 4.0;
static const double _disabledThumbSize = 3.0;
@override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
return isEnabled ? const Size.fromRadius(_thumbSize) : const Size.fromRadius(_disabledThumbSize);
}
static final Tween<double> sizeTween = new Tween<double>(
begin: _disabledThumbSize,
end: _thumbSize,
);
@override
void paint(
PaintingContext context,
Offset thumbCenter, {
Animation<double> activationAnimation,
Animation<double> enableAnimation,
bool isDiscrete,
TextPainter labelPainter,
RenderBox parentBox,
SliderThemeData sliderTheme,
TextDirection textDirection,
double value,
}) {
final Canvas canvas = context.canvas;
final ColorTween colorTween = new ColorTween(
begin: sliderTheme.disabledThumbColor,
end: sliderTheme.thumbColor,
);
final double size = _thumbSize * sizeTween.evaluate(enableAnimation);
final Path thumbPath = _triangle(size, thumbCenter);
canvas.drawPath(thumbPath, new Paint()..color = colorTween.evaluate(enableAnimation));
}
}
class _CustomValueIndicatorShape extends SliderComponentShape {
static const double _indicatorSize = 4.0;
static const double _disabledIndicatorSize = 3.0;
static const double _slideUpHeight = 40.0;
@override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
return new Size.fromRadius(isEnabled ? _indicatorSize : _disabledIndicatorSize);
}
static final Tween<double> sizeTween = new Tween<double>(
begin: _disabledIndicatorSize,
end: _indicatorSize,
);
@override
void paint(
PaintingContext context,
Offset thumbCenter, {
Animation<double> activationAnimation,
Animation<double> enableAnimation,
bool isDiscrete,
TextPainter labelPainter,
RenderBox parentBox,
SliderThemeData sliderTheme,
TextDirection textDirection,
double value,
}) {
final Canvas canvas = context.canvas;
final ColorTween enableColor = new ColorTween(
begin: sliderTheme.disabledThumbColor,
end: sliderTheme.valueIndicatorColor,
);
final Tween<double> slideUpTween = new Tween<double>(
begin: 0.0,
end: _slideUpHeight,
);
final double size = _indicatorSize * sizeTween.evaluate(enableAnimation);
final Offset slideUpOffset = new Offset(0.0, -slideUpTween.evaluate(activationAnimation));
final Path thumbPath = _triangle(
size,
thumbCenter + slideUpOffset,
invert: true,
);
final Color paintColor = enableColor.evaluate(enableAnimation).withAlpha((255.0 * activationAnimation.value).round());
canvas.drawPath(
thumbPath,
new Paint()..color = paintColor,
);
canvas.drawLine(
thumbCenter,
thumbCenter + slideUpOffset,
new Paint()
..color = paintColor
..style = PaintingStyle.stroke
..strokeWidth = 2.0);
labelPainter.paint(canvas, thumbCenter + slideUpOffset + new Offset(-labelPainter.width / 2.0, -labelPainter.height - 4.0));
}
}
class _SliderDemoState extends State<SliderDemo> {
double _value = 25.0;
double _discreteValue = 20.0;
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
return new Scaffold(
appBar: new AppBar(title: const Text('Sliders')),
body: new Padding(
......@@ -26,7 +140,7 @@ class _SliderDemoState extends State<SliderDemo> {
children: <Widget>[
new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget> [
children: <Widget>[
new Slider(
value: _value,
min: 0.0,
......@@ -35,21 +149,21 @@ class _SliderDemoState extends State<SliderDemo> {
setState(() {
_value = value;
});
}
},
),
const Text('Continuous'),
]
],
),
new Column(
mainAxisSize: MainAxisSize.min,
children: const <Widget> [
children: const <Widget>[
const Slider(value: 0.25, onChanged: null),
const Text('Disabled'),
]
],
),
new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget> [
children: <Widget>[
new Slider(
value: _discreteValue,
min: 0.0,
......@@ -60,11 +174,43 @@ class _SliderDemoState extends State<SliderDemo> {
setState(() {
_discreteValue = value;
});
}
},
),
const Text('Discrete'),
],
),
new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new SliderTheme(
data: theme.sliderTheme.copyWith(
activeRailColor: Colors.deepPurple,
inactiveRailColor: Colors.black26,
activeTickMarkColor: Colors.white70,
inactiveTickMarkColor: Colors.black,
overlayColor: Colors.black12,
thumbColor: Colors.deepPurple,
valueIndicatorColor: Colors.deepPurpleAccent,
thumbShape: new _CustomThumbShape(),
valueIndicatorShape: new _CustomValueIndicatorShape(),
valueIndicatorTextStyle: theme.accentTextTheme.body2.copyWith(color: Colors.black87),
),
child: new Slider(
value: _discreteValue,
min: 0.0,
max: 100.0,
divisions: 5,
label: '${_discreteValue.round()}',
onChanged: (double value) {
setState(() {
_discreteValue = value;
});
},
),
),
const Text('Discrete with Custom Theme'),
],
),
],
),
),
......
......@@ -578,7 +578,10 @@ class _RenderSlider extends RenderBox {
void _updateLabelPainter() {
if (label != null) {
_labelPainter
..text = new TextSpan(style: _theme.accentTextTheme.body2, text: label)
..text = new TextSpan(
style: _sliderTheme.valueIndicatorTextStyle,
text: label,
)
..textDirection = textDirection
..textScaleFactor = _mediaQueryData.textScaleFactor
..layout();
......@@ -849,31 +852,31 @@ class _RenderSlider extends RenderBox {
_valueIndicatorAnimation.status != AnimationStatus.dismissed) {
if (showValueIndicator) {
_sliderTheme.valueIndicatorShape.paint(
this,
context,
isDiscrete,
thumbCenter,
_valueIndicatorAnimation,
_enableAnimation,
_labelPainter,
_sliderTheme,
_textDirection,
value,
activationAnimation: _valueIndicatorAnimation,
enableAnimation: _enableAnimation,
isDiscrete: isDiscrete,
labelPainter: _labelPainter,
parentBox: this,
sliderTheme: _sliderTheme,
textDirection: _textDirection,
value: _value,
);
}
}
_sliderTheme.thumbShape.paint(
this,
context,
isDiscrete,
thumbCenter,
_overlayAnimation,
_enableAnimation,
label != null ? _labelPainter : null,
_sliderTheme,
_textDirection,
value,
activationAnimation: _valueIndicatorAnimation,
enableAnimation: _enableAnimation,
isDiscrete: isDiscrete,
labelPainter: _labelPainter,
parentBox: this,
sliderTheme: _sliderTheme,
textDirection: _textDirection,
value: _value,
);
}
......
......@@ -166,6 +166,7 @@ class ThemeData extends Diagnosticable {
primaryColor: primaryColor,
primaryColorLight: primaryColorLight,
primaryColorDark: primaryColorDark,
valueIndicatorTextStyle: accentTextTheme.body2,
);
return new ThemeData.raw(
brightness: brightness,
......
......@@ -25,17 +25,17 @@ class LoggingThumbShape extends SliderComponentShape {
@override
void paint(
RenderBox parentBox,
PaintingContext context,
bool isDiscrete,
Offset thumbCenter,
Offset thumbCenter, {
Animation<double> activationAnimation,
Animation<double> enableAnimation,
bool isDiscrete,
TextPainter labelPainter,
RenderBox parentBox,
SliderThemeData sliderTheme,
TextDirection textDirection,
double value,
) {
}) {
log.add(thumbCenter);
final Paint thumbPaint = new Paint()..color = Colors.red;
context.canvas.drawCircle(thumbCenter, 5.0, thumbPaint);
......
......@@ -104,11 +104,13 @@ void main() {
const Color customColor1 = const Color(0xcafefeed);
const Color customColor2 = const Color(0xdeadbeef);
const Color customColor3 = const Color(0xdecaface);
const Color customColor4 = const Color(0xfeedcafe);
final SliderThemeData sliderTheme = new SliderThemeData.fromPrimaryColors(
primaryColor: customColor1,
primaryColorDark: customColor2,
primaryColorLight: customColor3,
valueIndicatorTextStyle: new ThemeData.fallback().accentTextTheme.body2.copyWith(color: customColor4),
);
expect(sliderTheme.activeRailColor, equals(customColor1.withAlpha(0xff)));
......@@ -126,6 +128,7 @@ void main() {
expect(sliderTheme.thumbShape, equals(const isInstanceOf<RoundSliderThumbShape>()));
expect(sliderTheme.valueIndicatorShape, equals(const isInstanceOf<PaddleSliderValueIndicatorShape>()));
expect(sliderTheme.showValueIndicator, equals(ShowValueIndicator.onlyForDiscrete));
expect(sliderTheme.valueIndicatorTextStyle.color, equals(customColor4));
});
testWidgets('SliderThemeData lerps correctly', (WidgetTester tester) async {
......@@ -133,11 +136,13 @@ void main() {
primaryColor: Colors.black,
primaryColorDark: Colors.black,
primaryColorLight: Colors.black,
valueIndicatorTextStyle: new ThemeData.fallback().accentTextTheme.body2.copyWith(color: Colors.black),
);
final SliderThemeData sliderThemeWhite = new SliderThemeData.fromPrimaryColors(
primaryColor: Colors.white,
primaryColorDark: Colors.white,
primaryColorLight: Colors.white,
valueIndicatorTextStyle: new ThemeData.fallback().accentTextTheme.body2.copyWith(color: Colors.white),
);
final SliderThemeData lerp = SliderThemeData.lerp(sliderThemeBlack, sliderThemeWhite, 0.5);
const Color middleGrey = const Color(0xff7f7f7f);
......@@ -153,6 +158,7 @@ void main() {
expect(lerp.disabledThumbColor, equals(middleGrey.withAlpha(0x52)));
expect(lerp.overlayColor, equals(middleGrey.withAlpha(0x29)));
expect(lerp.valueIndicatorColor, equals(middleGrey.withAlpha(0xff)));
expect(lerp.valueIndicatorTextStyle.color, equals(middleGrey.withAlpha(0xff)));
});
testWidgets('Default slider thumb shape draws correctly', (WidgetTester tester) async {
......
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