Commit 7b549def authored by Adam Barth's avatar Adam Barth Committed by GitHub

Add RTL support to Slider and CupertinoSlider (#11822)

Fixes #11358
parent 3437b770
......@@ -161,6 +161,7 @@ class _CupertinoSliderRenderObjectWidget extends LeafRenderObjectWidget {
activeColor: activeColor,
onChanged: onChanged,
vsync: vsync,
textDirection: Directionality.of(context),
);
}
......@@ -170,7 +171,8 @@ class _CupertinoSliderRenderObjectWidget extends LeafRenderObjectWidget {
..value = value
..divisions = divisions
..activeColor = activeColor
..onChanged = onChanged;
..onChanged = onChanged
..textDirection = Directionality.of(context);
// Ticker provider cannot change since there's a 1:1 relationship between
// the _SliderRenderObjectWidget object and the _SliderState object.
}
......@@ -192,11 +194,14 @@ class _RenderCupertinoSlider extends RenderConstrainedBox implements SemanticsAc
Color activeColor,
ValueChanged<double> onChanged,
TickerProvider vsync,
@required TextDirection textDirection,
}) : assert(value != null && value >= 0.0 && value <= 1.0),
assert(textDirection != null),
_value = value,
_divisions = divisions,
_activeColor = activeColor,
_onChanged = onChanged,
_textDirection = textDirection,
super(additionalConstraints: const BoxConstraints.tightFor(width: _kSliderWidth, height: _kSliderHeight)) {
_drag = new HorizontalDragGestureRecognizer()
..onStart = _handleDragStart
......@@ -251,6 +256,16 @@ class _RenderCupertinoSlider extends RenderConstrainedBox implements SemanticsAc
markNeedsSemanticsUpdate(noGeometry: true);
}
TextDirection get textDirection => _textDirection;
TextDirection _textDirection;
set textDirection(TextDirection value) {
assert(value != null);
if (_textDirection == value)
return;
_textDirection = value;
markNeedsPaint();
}
AnimationController _position;
HorizontalDragGestureRecognizer _drag;
......@@ -265,7 +280,18 @@ class _RenderCupertinoSlider extends RenderConstrainedBox implements SemanticsAc
double get _trackLeft => _kPadding;
double get _trackRight => size.width - _kPadding;
double get _thumbCenter => lerpDouble(_trackLeft + CupertinoThumbPainter.radius, _trackRight - CupertinoThumbPainter.radius, _value);
double get _thumbCenter {
double visualPosition;
switch (textDirection) {
case TextDirection.rtl:
visualPosition = 1.0 - _value;
break;
case TextDirection.ltr:
visualPosition = _value;
break;
}
return lerpDouble(_trackLeft + CupertinoThumbPainter.radius, _trackRight - CupertinoThumbPainter.radius, visualPosition);
}
bool get isInteractive => onChanged != null;
......@@ -279,7 +305,15 @@ class _RenderCupertinoSlider extends RenderConstrainedBox implements SemanticsAc
void _handleDragUpdate(DragUpdateDetails details) {
if (isInteractive) {
final double extent = math.max(_kPadding, size.width - 2.0 * (_kPadding + CupertinoThumbPainter.radius));
_currentDragValue += details.primaryDelta / extent;
final double valueDelta = details.primaryDelta / extent;
switch (textDirection) {
case TextDirection.rtl:
_currentDragValue -= valueDelta;
break;
case TextDirection.ltr:
_currentDragValue += valueDelta;
break;
}
onChanged(_discretizedCurrentDragValue);
}
}
......@@ -304,9 +338,21 @@ class _RenderCupertinoSlider extends RenderConstrainedBox implements SemanticsAc
@override
void paint(PaintingContext context, Offset offset) {
final Canvas canvas = context.canvas;
final double value = _position.value;
double visualPosition;
Color leftColor;
Color rightColor;
switch (textDirection) {
case TextDirection.rtl:
visualPosition = 1.0 - _position.value;
leftColor = _kTrackColor;
rightColor = _activeColor;
break;
case TextDirection.ltr:
visualPosition = _position.value;
leftColor = _activeColor;
rightColor = _kTrackColor;
break;
}
final double trackCenter = offset.dy + size.height / 2.0;
final double trackLeft = offset.dx + _trackLeft;
......@@ -315,15 +361,16 @@ class _RenderCupertinoSlider extends RenderConstrainedBox implements SemanticsAc
final double trackRight = offset.dx + _trackRight;
final double trackActive = offset.dx + _thumbCenter;
final Canvas canvas = context.canvas;
final Paint paint = new Paint();
if (value > 0.0) {
paint.color = _activeColor;
if (visualPosition > 0.0) {
paint.color = rightColor;
canvas.drawRRect(new RRect.fromLTRBXY(trackLeft, trackTop, trackActive, trackBottom, 1.0, 1.0), paint);
}
if (value < 1.0) {
paint.color = _kTrackColor;
if (visualPosition < 1.0) {
paint.color = leftColor;
canvas.drawRRect(new RRect.fromLTRBXY(trackActive, trackTop, trackRight, trackBottom, 1.0, 1.0), paint);
}
......
......@@ -229,6 +229,7 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
textTheme: textTheme,
onChanged: onChanged,
vsync: vsync,
textDirection: Directionality.of(context),
);
}
......@@ -242,7 +243,8 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
..inactiveColor = inactiveColor
..thumbOpenAtMin = thumbOpenAtMin
..textTheme = textTheme
..onChanged = onChanged;
..onChanged = onChanged
..textDirection = Directionality.of(context);
// Ticker provider cannot change since there's a 1:1 relationship between
// the _SliderRenderObjectWidget object and the _SliderState object.
}
......@@ -290,14 +292,17 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
TextTheme textTheme,
ValueChanged<double> onChanged,
TickerProvider vsync,
@required TextDirection textDirection,
}) : assert(value != null && value >= 0.0 && value <= 1.0),
assert(textDirection != null),
_value = value,
_divisions = divisions,
_activeColor = activeColor,
_inactiveColor = inactiveColor,
_thumbOpenAtMin = thumbOpenAtMin,
_textTheme = textTheme,
_onChanged = onChanged {
_onChanged = onChanged,
_textDirection = textDirection {
this.label = label;
final GestureArenaTeam team = new GestureArenaTeam();
_drag = new HorizontalDragGestureRecognizer()
......@@ -415,6 +420,17 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
}
}
TextDirection get textDirection => _textDirection;
TextDirection _textDirection;
set textDirection(TextDirection value) {
assert(value != null);
if (_textDirection == value)
return;
_textDirection = value;
// TODO(abarth): Update _labelPainter's text direction.
markNeedsPaint();
}
double get _trackLength => size.width - 2.0 * _kReactionRadius;
Animation<double> _reaction;
......@@ -430,8 +446,19 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
bool get isInteractive => onChanged != null;
double _getValueFromVisualPosition(double visualPosition) {
switch (textDirection) {
case TextDirection.rtl:
return 1.0 - visualPosition;
case TextDirection.ltr:
return visualPosition;
}
return null;
}
double _getValueFromGlobalPosition(Offset globalPosition) {
return (globalToLocal(globalPosition).dx - _kReactionRadius) / _trackLength;
final double visualPosition = (globalToLocal(globalPosition).dx - _kReactionRadius) / _trackLength;
return _getValueFromVisualPosition(visualPosition);
}
double _discretize(double value) {
......@@ -452,7 +479,15 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
void _handleDragUpdate(DragUpdateDetails details) {
if (isInteractive) {
_currentDragValue += details.primaryDelta / _trackLength;
final double valueDelta = details.primaryDelta / _trackLength;
switch (textDirection) {
case TextDirection.rtl:
_currentDragValue -= valueDelta;
break;
case TextDirection.ltr:
_currentDragValue += valueDelta;
break;
}
onChanged(_discretize(_currentDragValue));
}
}
......@@ -523,6 +558,26 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
final double trackLength = size.width - 2 * _kReactionRadius;
final bool enabled = isInteractive;
final double value = _position.value;
final bool thumbAtMin = value == 0.0;
final Paint primaryPaint = new Paint()..color = enabled ? _activeColor : _inactiveColor;
final Paint trackPaint = new Paint()..color = _inactiveColor;
double visualPosition;
Paint leftPaint;
Paint rightPaint;
switch (textDirection) {
case TextDirection.rtl:
visualPosition = 1.0 - value;
leftPaint = trackPaint;
rightPaint = primaryPaint;
break;
case TextDirection.ltr:
visualPosition = value;
leftPaint = primaryPaint;
rightPaint = trackPaint;
break;
}
final double additionalHeightForLabel = _getAdditionalHeightForLabel(label);
final double trackCenter = offset.dy + (size.height - additionalHeightForLabel) / 2.0 + additionalHeightForLabel;
......@@ -530,26 +585,23 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
final double trackTop = trackCenter - 1.0;
final double trackBottom = trackCenter + 1.0;
final double trackRight = trackLeft + trackLength;
final double trackActive = trackLeft + trackLength * value;
final Paint primaryPaint = new Paint()..color = enabled ? _activeColor : _inactiveColor;
final Paint trackPaint = new Paint()..color = _inactiveColor;
final double trackActive = trackLeft + trackLength * visualPosition;
final Offset thumbCenter = new Offset(trackActive, trackCenter);
final double thumbRadius = enabled ? _kThumbRadiusTween.evaluate(_reaction) : _kDisabledThumbRadius;
if (enabled) {
if (value > 0.0)
canvas.drawRect(new Rect.fromLTRB(trackLeft, trackTop, trackActive, trackBottom), primaryPaint);
if (value < 1.0) {
if (visualPosition > 0.0)
canvas.drawRect(new Rect.fromLTRB(trackLeft, trackTop, trackActive, trackBottom), leftPaint);
if (visualPosition < 1.0) {
final bool hasBalloon = _reaction.status != AnimationStatus.dismissed && label != null;
final double trackActiveDelta = hasBalloon ? 0.0 : thumbRadius - 1.0;
canvas.drawRect(new Rect.fromLTRB(trackActive + trackActiveDelta, trackTop, trackRight, trackBottom), trackPaint);
canvas.drawRect(new Rect.fromLTRB(trackActive + trackActiveDelta, trackTop, trackRight, trackBottom), rightPaint);
}
} else {
if (value > 0.0)
if (visualPosition > 0.0)
canvas.drawRect(new Rect.fromLTRB(trackLeft, trackTop, trackActive - _kDisabledThumbRadius - 2, trackBottom), trackPaint);
if (value < 1.0)
if (visualPosition < 1.0)
canvas.drawRect(new Rect.fromLTRB(trackActive + _kDisabledThumbRadius + 2, trackTop, trackRight, trackBottom), trackPaint);
}
......@@ -589,7 +641,7 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
_labelPainter.paint(canvas, labelOffset);
return;
} else {
final Color reactionBaseColor = value == 0.0 ? _kActiveTrackColor : _activeColor;
final Color reactionBaseColor = thumbAtMin ? _kActiveTrackColor : _activeColor;
final Paint reactionPaint = new Paint()..color = reactionBaseColor.withAlpha(kRadialReactionAlpha);
canvas.drawCircle(thumbCenter, _kReactionRadiusTween.evaluate(_reaction), reactionPaint);
}
......@@ -597,7 +649,7 @@ class _RenderSlider extends RenderBox implements SemanticsActionHandler {
Paint thumbPaint = primaryPaint;
double thumbRadiusDelta = 0.0;
if (value == 0.0 && thumbOpenAtMin) {
if (thumbAtMin && thumbOpenAtMin) {
thumbPaint = trackPaint;
// This is destructive to trackPaint.
thumbPaint
......
......@@ -11,12 +11,13 @@ import 'package:flutter_test/flutter_test.dart';
import '../widgets/semantics_tester.dart';
void main() {
testWidgets('Slider does not move when tapped', (WidgetTester tester) async {
testWidgets('Slider does not move when tapped (LTR)', (WidgetTester tester) async {
final Key sliderKey = new UniqueKey();
double value = 0.0;
await tester.pumpWidget(
new StatefulBuilder(
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
......@@ -33,7 +34,41 @@ void main() {
);
},
),
);
));
expect(value, equals(0.0));
await tester.tap(find.byKey(sliderKey));
expect(value, equals(0.0));
await tester.pump(); // No animation should start.
// Check the transientCallbackCount before tearing down the widget to ensure
// that no animation is running.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
});
testWidgets('Slider does not move when tapped (RTL)', (WidgetTester tester) async {
final Key sliderKey = new UniqueKey();
double value = 0.0;
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.rtl,
child: new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
child: new CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
),
),
);
},
),
));
expect(value, equals(0.0));
await tester.tap(find.byKey(sliderKey));
......@@ -44,12 +79,14 @@ void main() {
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
});
testWidgets('Slider moves when dragged', (WidgetTester tester) async {
testWidgets('Slider moves when dragged (LTR)', (WidgetTester tester) async {
final Key sliderKey = new UniqueKey();
double value = 0.0;
await tester.pumpWidget(
new StatefulBuilder(
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
......@@ -66,7 +103,7 @@ void main() {
);
},
),
);
));
expect(value, equals(0.0));
final Offset topLeft = tester.getTopLeft(find.byKey(sliderKey));
......@@ -81,15 +118,54 @@ void main() {
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
});
testWidgets('Slider moves when dragged (RTL)', (WidgetTester tester) async {
final Key sliderKey = new UniqueKey();
double value = 0.0;
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.rtl,
child: new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
child: new CupertinoSlider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
),
),
);
},
),
));
expect(value, equals(0.0));
final Offset bottomRight = tester.getBottomRight(find.byKey(sliderKey));
const double unit = CupertinoThumbPainter.radius;
const double delta = 3.0 * unit;
await tester.dragFrom(bottomRight - const Offset(unit, unit), const Offset(-delta, 0.0));
final Size size = tester.getSize(find.byKey(sliderKey));
expect(value, equals(delta / (size.width - 2.0 * (8.0 + CupertinoThumbPainter.radius))));
await tester.pump(); // No animation should start.
// Check the transientCallbackCount before tearing down the widget to ensure
// that no animation is running.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
});
testWidgets('Slider Semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(
new CupertinoSlider(
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new CupertinoSlider(
value: 0.5,
onChanged: (double v) {},
),
);
));
expect(semantics, hasSemantics(
new TestSemantics.root(
......@@ -105,12 +181,13 @@ void main() {
));
// Disable slider
await tester.pumpWidget(
new CupertinoSlider(
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new CupertinoSlider(
value: 0.5,
onChanged: null,
),
);
));
expect(semantics, hasSemantics(
new TestSemantics.root(),
......
......@@ -13,27 +13,30 @@ import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart';
void main() {
testWidgets('Slider can move when tapped', (WidgetTester tester) async {
testWidgets('Slider can move when tapped (LTR)', (WidgetTester tester) async {
final Key sliderKey = new UniqueKey();
double value = 0.0;
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
child: new Slider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
new Directionality(
textDirection: TextDirection.ltr,
child: new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
child: new Slider(
key: sliderKey,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
),
),
),
);
},
);
},
),
),
);
......@@ -42,24 +45,30 @@ void main() {
expect(value, equals(0.5));
await tester.pump(); // No animation should start.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
final Offset topLeft = tester.getTopLeft(find.byKey(sliderKey));
final Offset bottomRight = tester.getBottomRight(find.byKey(sliderKey));
final Offset target = topLeft + (bottomRight - topLeft) / 4.0;
await tester.tapAt(target);
expect(value, closeTo(0.25, 0.05));
await tester.pump(); // No animation should start.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
});
testWidgets('Slider take on discrete values', (WidgetTester tester) async {
testWidgets('Slider can move when tapped (RTL)', (WidgetTester tester) async {
final Key sliderKey = new UniqueKey();
double value = 0.0;
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
child: new SizedBox(
width: 144.0 + 2 * 16.0, // _kPreferredTotalWidth
new Directionality(
textDirection: TextDirection.rtl,
child: new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
child: new Slider(
key: sliderKey,
min: 0.0,
max: 100.0,
divisions: 10,
value: value,
onChanged: (double newValue) {
setState(() {
......@@ -68,9 +77,58 @@ void main() {
},
),
),
),
);
},
);
},
),
),
);
expect(value, equals(0.0));
await tester.tap(find.byKey(sliderKey));
expect(value, equals(0.5));
await tester.pump(); // No animation should start.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
final Offset topLeft = tester.getTopLeft(find.byKey(sliderKey));
final Offset bottomRight = tester.getBottomRight(find.byKey(sliderKey));
final Offset target = topLeft + (bottomRight - topLeft) / 4.0;
await tester.tapAt(target);
expect(value, closeTo(0.75, 0.05));
await tester.pump(); // No animation should start.
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
});
testWidgets('Slider take on discrete values', (WidgetTester tester) async {
final Key sliderKey = new UniqueKey();
double value = 0.0;
await tester.pumpWidget(
new Directionality(
textDirection: TextDirection.ltr,
child: new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return new Material(
child: new Center(
child: new SizedBox(
width: 144.0 + 2 * 16.0, // _kPreferredTotalWidth
child: new Slider(
key: sliderKey,
min: 0.0,
max: 100.0,
divisions: 10,
value: value,
onChanged: (double newValue) {
setState(() {
value = newValue;
});
},
),
),
),
);
},
),
),
);
......@@ -95,12 +153,15 @@ void main() {
testWidgets('Slider can be given zero values',
(WidgetTester tester) async {
final List<double> log = <double>[];
await tester.pumpWidget(new Material(
child: new Slider(
value: 0.0,
min: 0.0,
max: 1.0,
onChanged: (double newValue) { log.add(newValue); },
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new Slider(
value: 0.0,
min: 0.0,
max: 1.0,
onChanged: (double newValue) { log.add(newValue); },
),
),
));
......@@ -108,12 +169,15 @@ void main() {
expect(log, <double>[0.5]);
log.clear();
await tester.pumpWidget(new Material(
child: new Slider(
value: 0.0,
min: 0.0,
max: 0.0,
onChanged: (double newValue) { log.add(newValue); },
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new Slider(
value: 0.0,
min: 0.0,
max: 0.0,
onChanged: (double newValue) { log.add(newValue); },
),
),
));
......@@ -127,14 +191,17 @@ void main() {
final Color customColor = const Color(0xFF4CD964);
final ThemeData theme = new ThemeData(platform: TargetPlatform.android);
Widget buildApp(Color activeColor) {
return new Material(
child: new Center(
child: new Theme(
data: theme,
child: new Slider(
value: 0.5,
activeColor: activeColor,
onChanged: (double newValue) {},
return new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new Center(
child: new Theme(
data: theme,
child: new Slider(
value: 0.5,
activeColor: activeColor,
onChanged: (double newValue) {},
),
),
),
),
......@@ -162,14 +229,17 @@ void main() {
final Color customColor = const Color(0xFF4CD964);
final ThemeData theme = new ThemeData(platform: TargetPlatform.android);
Widget buildApp(Color inactiveColor) {
return new Material(
child: new Center(
child: new Theme(
data: theme,
child: new Slider(
value: 0.5,
inactiveColor: inactiveColor,
onChanged: (double newValue) {},
return new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new Center(
child: new Theme(
data: theme,
child: new Slider(
value: 0.5,
inactiveColor: inactiveColor,
onChanged: (double newValue) {},
),
),
),
),
......@@ -188,15 +258,47 @@ void main() {
expect(sliderBox, paints..circle(color: theme.accentColor));
});
testWidgets('Slider can draw an open thumb at min',
testWidgets('Slider can draw an open thumb at min (LTR)',
(WidgetTester tester) async {
Widget buildApp(bool thumbOpenAtMin) {
return new Material(
child: new Center(
child: new Slider(
value: 0.0,
thumbOpenAtMin: thumbOpenAtMin,
onChanged: (double newValue) {},
return new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new Center(
child: new Slider(
value: 0.0,
thumbOpenAtMin: thumbOpenAtMin,
onChanged: (double newValue) {},
),
),
),
);
}
await tester.pumpWidget(buildApp(false));
final RenderBox sliderBox =
tester.firstRenderObject<RenderBox>(find.byType(Slider));
expect(sliderBox, paints..circle(style: PaintingStyle.fill));
expect(sliderBox, isNot(paints..circle()..circle()));
await tester.pumpWidget(buildApp(true));
expect(sliderBox, paints..circle(style: PaintingStyle.stroke));
expect(sliderBox, isNot(paints..circle()..circle()));
});
testWidgets('Slider can draw an open thumb at min (RTL)',
(WidgetTester tester) async {
Widget buildApp(bool thumbOpenAtMin) {
return new Directionality(
textDirection: TextDirection.rtl,
child: new Material(
child: new Center(
child: new Slider(
value: 0.0,
thumbOpenAtMin: thumbOpenAtMin,
onChanged: (double newValue) {},
),
),
),
);
......@@ -217,35 +319,69 @@ void main() {
testWidgets('Slider can tap in vertical scroller',
(WidgetTester tester) async {
double value = 0.0;
await tester.pumpWidget(new Material(
child: new ListView(
children: <Widget>[
new Slider(
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new ListView(
children: <Widget>[
new Slider(
value: value,
onChanged: (double newValue) {
value = newValue;
},
),
new Container(
height: 2000.0,
),
],
),
),
));
await tester.tap(find.byType(Slider));
expect(value, equals(0.5));
});
testWidgets('Slider drags immediately (LTR)', (WidgetTester tester) async {
double value = 0.0;
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new Center(
child: new Slider(
value: value,
onChanged: (double newValue) {
value = newValue;
},
),
new Container(
height: 2000.0,
),
],
),
),
));
await tester.tap(find.byType(Slider));
final Offset center = tester.getCenter(find.byType(Slider));
final TestGesture gesture = await tester.startGesture(center);
expect(value, equals(0.5));
await gesture.moveBy(const Offset(1.0, 0.0));
expect(value, greaterThan(0.5));
await gesture.up();
});
testWidgets('Slider drags immediately', (WidgetTester tester) async {
testWidgets('Slider drags immediately (RTL)', (WidgetTester tester) async {
double value = 0.0;
await tester.pumpWidget(new Material(
child: new Center(
child: new Slider(
value: value,
onChanged: (double newValue) {
value = newValue;
},
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.rtl,
child: new Material(
child: new Center(
child: new Slider(
value: value,
onChanged: (double newValue) {
value = newValue;
},
),
),
),
));
......@@ -257,42 +393,51 @@ void main() {
await gesture.moveBy(const Offset(1.0, 0.0));
expect(value, greaterThan(0.5));
expect(value, lessThan(0.5));
await gesture.up();
});
testWidgets('Slider sizing', (WidgetTester tester) async {
await tester.pumpWidget(const Material(
child: const Center(
child: const Slider(
value: 0.5,
onChanged: null,
await tester.pumpWidget(const Directionality(
textDirection: TextDirection.ltr,
child: const Material(
child: const Center(
child: const Slider(
value: 0.5,
onChanged: null,
),
),
),
));
expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(800.0, 600.0));
await tester.pumpWidget(const Material(
child: const Center(
child: const IntrinsicWidth(
child: const Slider(
value: 0.5,
onChanged: null,
await tester.pumpWidget(const Directionality(
textDirection: TextDirection.ltr,
child: const Material(
child: const Center(
child: const IntrinsicWidth(
child: const Slider(
value: 0.5,
onChanged: null,
),
),
),
),
));
expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(144.0 + 2.0 * 16.0, 600.0));
await tester.pumpWidget(const Material(
child: const Center(
child: const OverflowBox(
maxWidth: double.INFINITY,
maxHeight: double.INFINITY,
child: const Slider(
value: 0.5,
onChanged: null,
await tester.pumpWidget(const Directionality(
textDirection: TextDirection.ltr,
child: const Material(
child: const Center(
child: const OverflowBox(
maxWidth: double.INFINITY,
maxHeight: double.INFINITY,
child: const Slider(
value: 0.5,
onChanged: null,
),
),
),
),
......@@ -303,14 +448,15 @@ void main() {
testWidgets('Slider Semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(
new Material(
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new Slider(
value: 0.5,
onChanged: (double v) {},
),
),
);
));
expect(semantics, hasSemantics(
new TestSemantics.root(
......@@ -326,14 +472,15 @@ void main() {
));
// Disable slider
await tester.pumpWidget(
new Material(
await tester.pumpWidget(new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new Slider(
value: 0.5,
onChanged: null,
),
),
);
));
expect(semantics, hasSemantics(
new TestSemantics.root(),
......
......@@ -219,13 +219,16 @@ void main() {
await tester.pumpWidget(
new SemanticsDebugger(
child: new Material(
child: new Center(
child: new Slider(
value: value,
onChanged: (double newValue) {
value = newValue;
},
child: new Directionality(
textDirection: TextDirection.ltr,
child: new Material(
child: new Center(
child: new Slider(
value: value,
onChanged: (double newValue) {
value = newValue;
},
),
),
),
),
......
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