Make material slider respect textScaleFactor (#12511)
Make material slider respect textScaleFactor Fixes #5938
This commit is contained in:
parent
3470c682f4
commit
ba0618d35d
@ -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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
..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 {
|
|||||||
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 {
|
|||||||
_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 {
|
|||||||
_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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|||||||
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);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user