Commit ba0618d3 authored by gspencergoog's avatar gspencergoog Committed by GitHub

Make material slider respect textScaleFactor (#12511)

Make material slider respect textScaleFactor

Fixes #5938
parent 3470c682
...@@ -170,11 +170,28 @@ class Slider extends StatefulWidget { ...@@ -170,11 +170,28 @@ class Slider extends StatefulWidget {
} }
class _SliderState extends State<Slider> with TickerProviderStateMixin { class _SliderState extends State<Slider> with TickerProviderStateMixin {
_SliderState() {
_reactionController = new AnimationController(
duration: kRadialReactionDuration,
vsync: this,
);
}
void _handleChanged(double value) { void _handleChanged(double value) {
assert(widget.onChanged != null); assert(widget.onChanged != null);
widget.onChanged(value * (widget.max - widget.min) + widget.min); widget.onChanged(value * (widget.max - widget.min) + widget.min);
} }
@override
void dispose() {
_reactionController?.dispose();
super.dispose();
}
// Have to keep the reaction controller here so that we may dispose of it
// properly.
AnimationController _reactionController;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context)); assert(debugCheckHasMaterial(context));
...@@ -187,8 +204,10 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin { ...@@ -187,8 +204,10 @@ class _SliderState extends State<Slider> with TickerProviderStateMixin {
inactiveColor: widget.inactiveColor ?? theme.unselectedWidgetColor, inactiveColor: widget.inactiveColor ?? theme.unselectedWidgetColor,
thumbOpenAtMin: widget.thumbOpenAtMin, thumbOpenAtMin: widget.thumbOpenAtMin,
textTheme: theme.accentTextTheme, textTheme: theme.accentTextTheme,
textScaleFactor: MediaQuery.of(context, nullOk: true)?.textScaleFactor ?? 1.0,
onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null, onChanged: (widget.onChanged != null) && (widget.max > widget.min) ? _handleChanged : null,
vsync: this, vsync: this,
reactionController: _reactionController,
); );
} }
} }
...@@ -203,8 +222,10 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -203,8 +222,10 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
this.inactiveColor, this.inactiveColor,
this.thumbOpenAtMin, this.thumbOpenAtMin,
this.textTheme, this.textTheme,
this.textScaleFactor,
this.onChanged, this.onChanged,
this.vsync, this.vsync,
this.reactionController,
}) : super(key: key); }) : super(key: key);
final double value; final double value;
...@@ -214,8 +235,10 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -214,8 +235,10 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
final Color inactiveColor; final Color inactiveColor;
final bool thumbOpenAtMin; final bool thumbOpenAtMin;
final TextTheme textTheme; final TextTheme textTheme;
final double textScaleFactor;
final ValueChanged<double> onChanged; final ValueChanged<double> onChanged;
final TickerProvider vsync; final TickerProvider vsync;
final AnimationController reactionController;
@override @override
_RenderSlider createRenderObject(BuildContext context) { _RenderSlider createRenderObject(BuildContext context) {
...@@ -227,8 +250,10 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -227,8 +250,10 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
inactiveColor: inactiveColor, inactiveColor: inactiveColor,
thumbOpenAtMin: thumbOpenAtMin, thumbOpenAtMin: thumbOpenAtMin,
textTheme: textTheme, textTheme: textTheme,
textScaleFactor: textScaleFactor,
onChanged: onChanged, onChanged: onChanged,
vsync: vsync, vsync: vsync,
reactionController: reactionController,
textDirection: Directionality.of(context), textDirection: Directionality.of(context),
); );
} }
...@@ -243,6 +268,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -243,6 +268,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
..inactiveColor = inactiveColor ..inactiveColor = inactiveColor
..thumbOpenAtMin = thumbOpenAtMin ..thumbOpenAtMin = thumbOpenAtMin
..textTheme = textTheme ..textTheme = textTheme
..textScaleFactor = textScaleFactor
..onChanged = onChanged ..onChanged = onChanged
..textDirection = Directionality.of(context); ..textDirection = Directionality.of(context);
// Ticker provider cannot change since there's a 1:1 relationship between // Ticker provider cannot change since there's a 1:1 relationship between
...@@ -290,9 +316,11 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { ...@@ -290,9 +316,11 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
Color inactiveColor, Color inactiveColor,
bool thumbOpenAtMin, bool thumbOpenAtMin,
TextTheme textTheme, TextTheme textTheme,
double textScaleFactor,
ValueChanged<double> onChanged, ValueChanged<double> onChanged,
TickerProvider vsync, TickerProvider vsync,
@required TextDirection textDirection, @required TextDirection textDirection,
@required AnimationController reactionController,
}) : assert(value != null && value >= 0.0 && value <= 1.0), }) : assert(value != null && value >= 0.0 && value <= 1.0),
assert(textDirection != null), assert(textDirection != null),
_label = label, _label = label,
...@@ -302,6 +330,7 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { ...@@ -302,6 +330,7 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
_inactiveColor = inactiveColor, _inactiveColor = inactiveColor,
_thumbOpenAtMin = thumbOpenAtMin, _thumbOpenAtMin = thumbOpenAtMin,
_textTheme = textTheme, _textTheme = textTheme,
_textScaleFactor = textScaleFactor,
_onChanged = onChanged, _onChanged = onChanged,
_textDirection = textDirection { _textDirection = textDirection {
_updateLabelPainter(); _updateLabelPainter();
...@@ -314,10 +343,7 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { ...@@ -314,10 +343,7 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
_tap = new TapGestureRecognizer() _tap = new TapGestureRecognizer()
..team = team ..team = team
..onTapUp = _handleTapUp; ..onTapUp = _handleTapUp;
_reactionController = new AnimationController( _reactionController = reactionController;
duration: kRadialReactionDuration,
vsync: vsync,
);
_reaction = new CurvedAnimation( _reaction = new CurvedAnimation(
parent: _reactionController, parent: _reactionController,
curve: Curves.fastOutSlowIn curve: Curves.fastOutSlowIn
...@@ -396,6 +422,16 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { ...@@ -396,6 +422,16 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
markNeedsPaint(); markNeedsPaint();
} }
double get textScaleFactor => _textScaleFactor;
double _textScaleFactor;
set textScaleFactor(double value) {
if (value == _textScaleFactor)
return;
_textScaleFactor = value;
_updateLabelPainter();
markNeedsPaint();
}
ValueChanged<double> get onChanged => _onChanged; ValueChanged<double> get onChanged => _onChanged;
ValueChanged<double> _onChanged; ValueChanged<double> _onChanged;
set onChanged(ValueChanged<double> value) { set onChanged(ValueChanged<double> value) {
...@@ -421,10 +457,9 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { ...@@ -421,10 +457,9 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
void _updateLabelPainter() { void _updateLabelPainter() {
if (label != null) { if (label != null) {
// TODO(abarth): Handle textScaleFactor. https://github.com/flutter/flutter/issues/5938
_labelPainter _labelPainter
..text = new TextSpan( ..text = new TextSpan(
style: _textTheme.body1.copyWith(fontSize: 10.0), style: _textTheme.body1.copyWith(fontSize: 10.0 * _textScaleFactor),
text: label, text: label,
) )
..textDirection = textDirection ..textDirection = textDirection
...@@ -628,9 +663,15 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler { ...@@ -628,9 +663,15 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
} }
if (label != null) { if (label != null) {
final Offset center = new Offset(trackActive, _kLabelBalloonCenterTween.evaluate(_reaction) + trackCenter); final Offset center = new Offset(
final double radius = _kLabelBalloonRadiusTween.evaluate(_reaction); trackActive,
final Offset tip = new Offset(trackActive, _kLabelBalloonTipTween.evaluate(_reaction) + trackCenter); _kLabelBalloonCenterTween.evaluate(_reaction) * textScaleFactor + trackCenter
);
final double radius = _kLabelBalloonRadiusTween.evaluate(_reaction) * textScaleFactor;
final Offset tip = new Offset(
trackActive,
_kLabelBalloonTipTween.evaluate(_reaction) * textScaleFactor + trackCenter
);
final double tipAttachment = _kLabelBalloonTipAttachmentRatio * radius; final double tipAttachment = _kLabelBalloonTipAttachmentRatio * radius;
canvas.drawCircle(center, radius, primaryPaint); canvas.drawCircle(center, radius, primaryPaint);
......
...@@ -445,6 +445,71 @@ void main() { ...@@ -445,6 +445,71 @@ void main() {
expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(144.0 + 2.0 * 16.0, 32.0)); expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(144.0 + 2.0 * 16.0, 32.0));
}); });
testWidgets('discrete Slider respects textScaleFactor', (WidgetTester tester) async {
final Key sliderKey = new UniqueKey();
double value = 0.0;
Widget buildSlider({ double textScaleFactor }) {
return new Directionality(
textDirection: TextDirection.ltr,
child: new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new MediaQuery(
data: new MediaQueryData(textScaleFactor: textScaleFactor),
child: new Material(
child: new Center(
child: new OverflowBox(
maxWidth: double.INFINITY,
maxHeight: double.INFINITY,
child: new Slider(
key: sliderKey,
min: 0.0,
max: 100.0,
divisions: 10,
label: '${value.round()}',
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
),
),
),
),
);
},
),
);
}
await tester.pumpWidget(buildSlider(textScaleFactor: 1.0));
Offset center = tester.getCenter(find.byType(Slider));
TestGesture gesture = await tester.startGesture(center);
await gesture.moveBy(const Offset(10.0, 0.0));
expect(
tester.renderObject(find.byType(Slider)),
paints..circle(radius: 6.0, x: 16.0, y: 44.0)
);
await gesture.up();
await tester.pump(const Duration(seconds: 1));
await tester.pumpWidget(buildSlider(textScaleFactor: 2.0));
center = tester.getCenter(find.byType(Slider));
gesture = await tester.startGesture(center);
await gesture.moveBy(const Offset(10.0, 0.0));
expect(
tester.renderObject(find.byType(Slider)),
paints..circle(radius: 12.0, x: 16.0, y: 44.0)
);
await gesture.up();
await tester.pump(const Duration(seconds: 1));
});
testWidgets('Slider Semantics', (WidgetTester tester) async { testWidgets('Slider Semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester); final SemanticsTester semantics = new SemanticsTester(tester);
......
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