mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
parent
3437b77007
commit
7b549def56
@ -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,7 @@ void main() {
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
));
|
||||
|
||||
expect(value, equals(0.0));
|
||||
await tester.tap(find.byKey(sliderKey));
|
||||
@ -44,12 +45,13 @@ void main() {
|
||||
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
||||
});
|
||||
|
||||
testWidgets('Slider moves when dragged', (WidgetTester tester) async {
|
||||
testWidgets('Slider does not move when tapped (RTL)', (WidgetTester tester) async {
|
||||
final Key sliderKey = new UniqueKey();
|
||||
double value = 0.0;
|
||||
|
||||
await tester.pumpWidget(
|
||||
new StatefulBuilder(
|
||||
await tester.pumpWidget(new Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: new StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return new Material(
|
||||
child: new Center(
|
||||
@ -66,7 +68,42 @@ 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 moves when dragged (LTR)', (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 CupertinoSlider(
|
||||
key: sliderKey,
|
||||
value: value,
|
||||
onChanged: (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
));
|
||||
|
||||
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,6 +45,58 @@ 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 can 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 Slider(
|
||||
key: sliderKey,
|
||||
value: value,
|
||||
onChanged: (double newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
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 {
|
||||
@ -49,28 +104,31 @@ void main() {
|
||||
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
|
||||
child: new Slider(
|
||||
key: sliderKey,
|
||||
min: 0.0,
|
||||
max: 100.0,
|
||||
divisions: 10,
|
||||
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 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,19 +319,22 @@ 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(
|
||||
value: value,
|
||||
onChanged: (double newValue) {
|
||||
value = newValue;
|
||||
},
|
||||
),
|
||||
new Container(
|
||||
height: 2000.0,
|
||||
),
|
||||
],
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
@ -237,15 +342,18 @@ void main() {
|
||||
expect(value, equals(0.5));
|
||||
});
|
||||
|
||||
testWidgets('Slider drags immediately', (WidgetTester tester) async {
|
||||
testWidgets('Slider drags immediately (LTR)', (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.ltr,
|
||||
child: new Material(
|
||||
child: new Center(
|
||||
child: new Slider(
|
||||
value: value,
|
||||
onChanged: (double newValue) {
|
||||
value = newValue;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
@ -262,20 +370,39 @@ void main() {
|
||||
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,
|
||||
testWidgets('Slider drags immediately (RTL)', (WidgetTester tester) async {
|
||||
double value = 0.0;
|
||||
await tester.pumpWidget(new Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: new Material(
|
||||
child: new Center(
|
||||
child: new Slider(
|
||||
value: value,
|
||||
onChanged: (double newValue) {
|
||||
value = newValue;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
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(
|
||||
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, lessThan(0.5));
|
||||
|
||||
await gesture.up();
|
||||
});
|
||||
|
||||
testWidgets('Slider sizing', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: const Material(
|
||||
child: const Center(
|
||||
child: const Slider(
|
||||
value: 0.5,
|
||||
onChanged: null,
|
||||
@ -283,16 +410,34 @@ void main() {
|
||||
),
|
||||
),
|
||||
));
|
||||
expect(tester.renderObject<RenderBox>(find.byType(Slider)).size, const Size(800.0, 600.0));
|
||||
|
||||
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;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user