Add slider minimum interaction time (#15358)
This change makes the discrete slider show the value indicator for a minimum amount of time for any interaction (tap, drag).
This commit is contained in:
parent
fc96326b9c
commit
d28e9aa5c9
@ -2,11 +2,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/scheduler.dart' show timeDilation;
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
@ -212,41 +214,55 @@ class Slider extends StatefulWidget {
|
|||||||
|
|
||||||
class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
class _SliderState extends State<Slider> with TickerProviderStateMixin {
|
||||||
static const Duration enableAnimationDuration = const Duration(milliseconds: 75);
|
static const Duration enableAnimationDuration = const Duration(milliseconds: 75);
|
||||||
static const Duration positionAnimationDuration = const Duration(milliseconds: 75);
|
static const Duration valueIndicatorAnimationDuration = const Duration(milliseconds: 100);
|
||||||
|
|
||||||
// Animation controller that is run when interactions occur (taps, drags,
|
// Animation controller that is run when the overlay (a.k.a radial reaction)
|
||||||
// etc.).
|
// is shown in response to user interaction.
|
||||||
AnimationController reactionController;
|
AnimationController overlayController;
|
||||||
|
// Animation controller that is run when the value indicator is being shown
|
||||||
|
// or hidden.
|
||||||
|
AnimationController valueIndicatorController;
|
||||||
// Animation controller that is run when enabling/disabling the slider.
|
// Animation controller that is run when enabling/disabling the slider.
|
||||||
AnimationController enableController;
|
AnimationController enableController;
|
||||||
// Animation controller that is run when transitioning between one value
|
// Animation controller that is run when transitioning between one value
|
||||||
// and the next on a discrete slider.
|
// and the next on a discrete slider.
|
||||||
AnimationController positionController;
|
AnimationController positionController;
|
||||||
|
Timer interactionTimer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
reactionController = new AnimationController(
|
overlayController = new AnimationController(
|
||||||
duration: kRadialReactionDuration,
|
duration: kRadialReactionDuration,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
|
valueIndicatorController = new AnimationController(
|
||||||
|
duration: valueIndicatorAnimationDuration,
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
enableController = new AnimationController(
|
enableController = new AnimationController(
|
||||||
duration: enableAnimationDuration,
|
duration: enableAnimationDuration,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
positionController = new AnimationController(
|
positionController = new AnimationController(
|
||||||
duration: positionAnimationDuration,
|
duration: Duration.zero,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
|
// Create timer in a cancelled state, so that we don't have to
|
||||||
|
// check for null below.
|
||||||
|
interactionTimer = new Timer(Duration.zero, () {});
|
||||||
|
interactionTimer.cancel();
|
||||||
enableController.value = widget.onChanged != null ? 1.0 : 0.0;
|
enableController.value = widget.onChanged != null ? 1.0 : 0.0;
|
||||||
positionController.value = widget.value;
|
positionController.value = _unlerp(widget.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
reactionController.dispose();
|
overlayController.dispose();
|
||||||
|
valueIndicatorController.dispose();
|
||||||
enableController.dispose();
|
enableController.dispose();
|
||||||
positionController.dispose();
|
positionController.dispose();
|
||||||
|
interactionTimer?.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,15 +374,6 @@ class _SliderRenderObjectWidget extends LeafRenderObjectWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const double _overlayRadius = 16.0;
|
|
||||||
const double _overlayDiameter = _overlayRadius * 2.0;
|
|
||||||
const double _railHeight = 2.0;
|
|
||||||
const double _preferredRailWidth = 144.0;
|
|
||||||
const double _preferredTotalWidth = _preferredRailWidth + _overlayDiameter;
|
|
||||||
|
|
||||||
const double _adjustmentUnit = 0.1; // Matches iOS implementation of material slider.
|
|
||||||
final Tween<double> _overlayRadiusTween = new Tween<double>(begin: 0.0, end: _overlayRadius);
|
|
||||||
|
|
||||||
class _RenderSlider extends RenderBox {
|
class _RenderSlider extends RenderBox {
|
||||||
_RenderSlider({
|
_RenderSlider({
|
||||||
@required double value,
|
@required double value,
|
||||||
@ -403,8 +410,12 @@ class _RenderSlider extends RenderBox {
|
|||||||
..onTapDown = _handleTapDown
|
..onTapDown = _handleTapDown
|
||||||
..onTapUp = _handleTapUp
|
..onTapUp = _handleTapUp
|
||||||
..onTapCancel = _endInteraction;
|
..onTapCancel = _endInteraction;
|
||||||
_reaction = new CurvedAnimation(
|
_overlayAnimation = new CurvedAnimation(
|
||||||
parent: _state.reactionController,
|
parent: _state.overlayController,
|
||||||
|
curve: Curves.fastOutSlowIn,
|
||||||
|
);
|
||||||
|
_valueIndicatorAnimation = new CurvedAnimation(
|
||||||
|
parent: _state.valueIndicatorController,
|
||||||
curve: Curves.fastOutSlowIn,
|
curve: Curves.fastOutSlowIn,
|
||||||
);
|
);
|
||||||
_enableAnimation = new CurvedAnimation(
|
_enableAnimation = new CurvedAnimation(
|
||||||
@ -413,11 +424,34 @@ class _RenderSlider extends RenderBox {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
double get value => _value;
|
static const Duration _positionAnimationDuration = const Duration(milliseconds: 75);
|
||||||
double _value;
|
static const double _overlayRadius = 16.0;
|
||||||
|
static const double _overlayDiameter = _overlayRadius * 2.0;
|
||||||
|
static const double _railHeight = 2.0;
|
||||||
|
static const double _preferredRailWidth = 144.0;
|
||||||
|
static const double _preferredTotalWidth = _preferredRailWidth + _overlayDiameter;
|
||||||
|
static const Duration _minimumInteractionTime = const Duration(milliseconds: 500);
|
||||||
|
static const double _adjustmentUnit = 0.1; // Matches iOS implementation of material slider.
|
||||||
|
static final Tween<double> _overlayRadiusTween = new Tween<double>(begin: 0.0, end: _overlayRadius);
|
||||||
|
|
||||||
_SliderState _state;
|
_SliderState _state;
|
||||||
|
Animation<double> _overlayAnimation;
|
||||||
|
Animation<double> _valueIndicatorAnimation;
|
||||||
|
Animation<double> _enableAnimation;
|
||||||
|
final TextPainter _labelPainter = new TextPainter();
|
||||||
|
HorizontalDragGestureRecognizer _drag;
|
||||||
|
TapGestureRecognizer _tap;
|
||||||
|
bool _active = false;
|
||||||
|
double _currentDragValue = 0.0;
|
||||||
|
|
||||||
|
double get _railLength => size.width - _overlayDiameter;
|
||||||
|
|
||||||
|
bool get isInteractive => onChanged != null;
|
||||||
|
|
||||||
|
bool get isDiscrete => divisions != null && divisions > 0;
|
||||||
|
|
||||||
|
double get value => _value;
|
||||||
|
double _value;
|
||||||
set value(double newValue) {
|
set value(double newValue) {
|
||||||
assert(newValue != null && newValue >= 0.0 && newValue <= 1.0);
|
assert(newValue != null && newValue >= 0.0 && newValue <= 1.0);
|
||||||
final double convertedValue = isDiscrete ? _discretize(newValue) : newValue;
|
final double convertedValue = isDiscrete ? _discretize(newValue) : newValue;
|
||||||
@ -426,6 +460,14 @@ class _RenderSlider extends RenderBox {
|
|||||||
}
|
}
|
||||||
_value = convertedValue;
|
_value = convertedValue;
|
||||||
if (isDiscrete) {
|
if (isDiscrete) {
|
||||||
|
// Reset the duration to match the distance that we're traveling, so that
|
||||||
|
// whatever the distance, we still do it in _positionAnimationDuration,
|
||||||
|
// and if we get re-targeted in the middle, it still takes that long to
|
||||||
|
// get to the new location.
|
||||||
|
final double distance = (_value - _state.positionController.value).abs();
|
||||||
|
_state.positionController.duration = distance != 0.0
|
||||||
|
? _positionAnimationDuration * (1.0 / distance)
|
||||||
|
: 0.0;
|
||||||
_state.positionController.animateTo(convertedValue, curve: Curves.easeInOut);
|
_state.positionController.animateTo(convertedValue, curve: Curves.easeInOut);
|
||||||
} else {
|
} else {
|
||||||
_state.positionController.value = convertedValue;
|
_state.positionController.value = convertedValue;
|
||||||
@ -514,6 +556,25 @@ class _RenderSlider extends RenderBox {
|
|||||||
_updateLabelPainter();
|
_updateLabelPainter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get showValueIndicator {
|
||||||
|
bool showValueIndicator;
|
||||||
|
switch (_sliderTheme.showValueIndicator) {
|
||||||
|
case ShowValueIndicator.onlyForDiscrete:
|
||||||
|
showValueIndicator = isDiscrete;
|
||||||
|
break;
|
||||||
|
case ShowValueIndicator.onlyForContinuous:
|
||||||
|
showValueIndicator = !isDiscrete;
|
||||||
|
break;
|
||||||
|
case ShowValueIndicator.always:
|
||||||
|
showValueIndicator = true;
|
||||||
|
break;
|
||||||
|
case ShowValueIndicator.never:
|
||||||
|
showValueIndicator = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return showValueIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
void _updateLabelPainter() {
|
void _updateLabelPainter() {
|
||||||
if (label != null) {
|
if (label != null) {
|
||||||
_labelPainter
|
_labelPainter
|
||||||
@ -530,31 +591,19 @@ class _RenderSlider extends RenderBox {
|
|||||||
markNeedsLayout();
|
markNeedsLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
double get _railLength => size.width - _overlayDiameter;
|
|
||||||
|
|
||||||
Animation<double> _reaction;
|
|
||||||
Animation<double> _enableAnimation;
|
|
||||||
final TextPainter _labelPainter = new TextPainter();
|
|
||||||
HorizontalDragGestureRecognizer _drag;
|
|
||||||
TapGestureRecognizer _tap;
|
|
||||||
bool _active = false;
|
|
||||||
double _currentDragValue = 0.0;
|
|
||||||
|
|
||||||
bool get isInteractive => onChanged != null;
|
|
||||||
|
|
||||||
bool get isDiscrete => divisions != null && divisions > 0;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void attach(PipelineOwner owner) {
|
void attach(PipelineOwner owner) {
|
||||||
super.attach(owner);
|
super.attach(owner);
|
||||||
_reaction.addListener(markNeedsPaint);
|
_overlayAnimation.addListener(markNeedsPaint);
|
||||||
|
_valueIndicatorAnimation.addListener(markNeedsPaint);
|
||||||
_enableAnimation.addListener(markNeedsPaint);
|
_enableAnimation.addListener(markNeedsPaint);
|
||||||
_state.positionController.addListener(markNeedsPaint);
|
_state.positionController.addListener(markNeedsPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void detach() {
|
void detach() {
|
||||||
_reaction.removeListener(markNeedsPaint);
|
_overlayAnimation.removeListener(markNeedsPaint);
|
||||||
|
_valueIndicatorAnimation.removeListener(markNeedsPaint);
|
||||||
_enableAnimation.removeListener(markNeedsPaint);
|
_enableAnimation.removeListener(markNeedsPaint);
|
||||||
_state.positionController.removeListener(markNeedsPaint);
|
_state.positionController.removeListener(markNeedsPaint);
|
||||||
super.detach();
|
super.detach();
|
||||||
@ -588,7 +637,19 @@ class _RenderSlider extends RenderBox {
|
|||||||
_active = true;
|
_active = true;
|
||||||
_currentDragValue = _getValueFromGlobalPosition(globalPosition);
|
_currentDragValue = _getValueFromGlobalPosition(globalPosition);
|
||||||
onChanged(_discretize(_currentDragValue));
|
onChanged(_discretize(_currentDragValue));
|
||||||
_state.reactionController.forward();
|
_state.overlayController.forward();
|
||||||
|
if (showValueIndicator) {
|
||||||
|
_state.valueIndicatorController.forward();
|
||||||
|
if (_state.interactionTimer.isActive) {
|
||||||
|
_state.interactionTimer.cancel();
|
||||||
|
}
|
||||||
|
_state.interactionTimer = new Timer(_minimumInteractionTime * timeDilation, () {
|
||||||
|
if (!_active && _state.valueIndicatorController.status == AnimationStatus.completed) {
|
||||||
|
_state.valueIndicatorController.reverse();
|
||||||
|
}
|
||||||
|
_state.interactionTimer.cancel();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,7 +657,10 @@ class _RenderSlider extends RenderBox {
|
|||||||
if (_active) {
|
if (_active) {
|
||||||
_active = false;
|
_active = false;
|
||||||
_currentDragValue = 0.0;
|
_currentDragValue = 0.0;
|
||||||
_state.reactionController.reverse();
|
_state.overlayController.reverse();
|
||||||
|
if (showValueIndicator && !_state.interactionTimer.isActive) {
|
||||||
|
_state.valueIndicatorController.reverse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,15 +760,15 @@ class _RenderSlider extends RenderBox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _paintOverlay(Canvas canvas, Offset center) {
|
void _paintOverlay(Canvas canvas, Offset center) {
|
||||||
if (!_reaction.isDismissed) {
|
if (!_overlayAnimation.isDismissed) {
|
||||||
// TODO(gspencer) : We don't really follow the spec here for overlays.
|
// TODO(gspencer) : We don't really follow the spec here for overlays.
|
||||||
// The spec says to use 16% opacity for drawing over light material,
|
// The spec says to use 16% opacity for drawing over light material,
|
||||||
// and 32% for colored material, but we don't really have a way to
|
// and 32% for colored material, but we don't really have a way to
|
||||||
// know what the underlying color is, so there's no easy way to
|
// know what the underlying color is, so there's no easy way to
|
||||||
// implement this. Choosing the "light" version for now.
|
// implement this. Choosing the "light" version for now.
|
||||||
final Paint reactionPaint = new Paint()..color = _sliderTheme.overlayColor;
|
final Paint overlayPaint = new Paint()..color = _sliderTheme.overlayColor;
|
||||||
final double radius = _overlayRadiusTween.evaluate(_reaction);
|
final double radius = _overlayRadiusTween.evaluate(_overlayAnimation);
|
||||||
canvas.drawCircle(center, radius, reactionPaint);
|
canvas.drawCircle(center, radius, overlayPaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -781,29 +845,15 @@ class _RenderSlider extends RenderBox {
|
|||||||
rightTickMarkPaint,
|
rightTickMarkPaint,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isInteractive && _reaction.status != AnimationStatus.dismissed && label != null) {
|
if (isInteractive && label != null &&
|
||||||
bool showValueIndicator;
|
_valueIndicatorAnimation.status != AnimationStatus.dismissed) {
|
||||||
switch (_sliderTheme.showValueIndicator) {
|
|
||||||
case ShowValueIndicator.onlyForDiscrete:
|
|
||||||
showValueIndicator = isDiscrete;
|
|
||||||
break;
|
|
||||||
case ShowValueIndicator.onlyForContinuous:
|
|
||||||
showValueIndicator = !isDiscrete;
|
|
||||||
break;
|
|
||||||
case ShowValueIndicator.always:
|
|
||||||
showValueIndicator = true;
|
|
||||||
break;
|
|
||||||
case ShowValueIndicator.never:
|
|
||||||
showValueIndicator = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (showValueIndicator) {
|
if (showValueIndicator) {
|
||||||
_sliderTheme.valueIndicatorShape.paint(
|
_sliderTheme.valueIndicatorShape.paint(
|
||||||
this,
|
this,
|
||||||
context,
|
context,
|
||||||
isDiscrete,
|
isDiscrete,
|
||||||
thumbCenter,
|
thumbCenter,
|
||||||
_reaction,
|
_valueIndicatorAnimation,
|
||||||
_enableAnimation,
|
_enableAnimation,
|
||||||
_labelPainter,
|
_labelPainter,
|
||||||
_sliderTheme,
|
_sliderTheme,
|
||||||
@ -818,7 +868,7 @@ class _RenderSlider extends RenderBox {
|
|||||||
context,
|
context,
|
||||||
isDiscrete,
|
isDiscrete,
|
||||||
thumbCenter,
|
thumbCenter,
|
||||||
_reaction,
|
_overlayAnimation,
|
||||||
_enableAnimation,
|
_enableAnimation,
|
||||||
label != null ? _labelPainter : null,
|
label != null ? _labelPainter : null,
|
||||||
_sliderTheme,
|
_sliderTheme,
|
||||||
|
@ -469,19 +469,19 @@ class SliderThemeData extends Diagnosticable {
|
|||||||
);
|
);
|
||||||
description.add(new DiagnosticsProperty<Color>('activeRailColor', activeRailColor, defaultValue: defaultData.activeRailColor));
|
description.add(new DiagnosticsProperty<Color>('activeRailColor', activeRailColor, defaultValue: defaultData.activeRailColor));
|
||||||
description.add(new DiagnosticsProperty<Color>('inactiveRailColor', inactiveRailColor, defaultValue: defaultData.inactiveRailColor));
|
description.add(new DiagnosticsProperty<Color>('inactiveRailColor', inactiveRailColor, defaultValue: defaultData.inactiveRailColor));
|
||||||
description.add(new DiagnosticsProperty<Color>('disabledActiveRailColor', disabledActiveRailColor, defaultValue: defaultData.disabledActiveRailColor));
|
description.add(new DiagnosticsProperty<Color>('disabledActiveRailColor', disabledActiveRailColor, defaultValue: defaultData.disabledActiveRailColor, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<Color>('disabledInactiveRailColor', disabledInactiveRailColor, defaultValue: defaultData.disabledInactiveRailColor));
|
description.add(new DiagnosticsProperty<Color>('disabledInactiveRailColor', disabledInactiveRailColor, defaultValue: defaultData.disabledInactiveRailColor, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<Color>('activeTickMarkColor', activeTickMarkColor, defaultValue: defaultData.activeTickMarkColor));
|
description.add(new DiagnosticsProperty<Color>('activeTickMarkColor', activeTickMarkColor, defaultValue: defaultData.activeTickMarkColor, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<Color>('inactiveTickMarkColor', inactiveTickMarkColor, defaultValue: defaultData.inactiveTickMarkColor));
|
description.add(new DiagnosticsProperty<Color>('inactiveTickMarkColor', inactiveTickMarkColor, defaultValue: defaultData.inactiveTickMarkColor, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<Color>('disabledActiveTickMarkColor', disabledActiveTickMarkColor, defaultValue: defaultData.disabledActiveTickMarkColor));
|
description.add(new DiagnosticsProperty<Color>('disabledActiveTickMarkColor', disabledActiveTickMarkColor, defaultValue: defaultData.disabledActiveTickMarkColor, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<Color>('disabledInactiveTickMarkColor', disabledInactiveTickMarkColor, defaultValue: defaultData.disabledInactiveTickMarkColor));
|
description.add(new DiagnosticsProperty<Color>('disabledInactiveTickMarkColor', disabledInactiveTickMarkColor, defaultValue: defaultData.disabledInactiveTickMarkColor, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<Color>('thumbColor', thumbColor, defaultValue: defaultData.thumbColor));
|
description.add(new DiagnosticsProperty<Color>('thumbColor', thumbColor, defaultValue: defaultData.thumbColor));
|
||||||
description.add(new DiagnosticsProperty<Color>('disabledThumbColor', disabledThumbColor, defaultValue: defaultData.disabledThumbColor));
|
description.add(new DiagnosticsProperty<Color>('disabledThumbColor', disabledThumbColor, defaultValue: defaultData.disabledThumbColor, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<Color>('overlayColor', overlayColor, defaultValue: defaultData.overlayColor));
|
description.add(new DiagnosticsProperty<Color>('overlayColor', overlayColor, defaultValue: defaultData.overlayColor, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<Color>('valueIndicatorColor', valueIndicatorColor, defaultValue: defaultData.valueIndicatorColor));
|
description.add(new DiagnosticsProperty<Color>('valueIndicatorColor', valueIndicatorColor, defaultValue: defaultData.valueIndicatorColor));
|
||||||
description.add(new DiagnosticsProperty<SliderComponentShape>('thumbShape', thumbShape, defaultValue: defaultData.thumbShape));
|
description.add(new DiagnosticsProperty<SliderComponentShape>('thumbShape', thumbShape, defaultValue: defaultData.thumbShape, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<SliderComponentShape>('valueIndicatorShape', valueIndicatorShape, defaultValue: defaultData.valueIndicatorShape));
|
description.add(new DiagnosticsProperty<SliderComponentShape>('valueIndicatorShape', valueIndicatorShape, defaultValue: defaultData.valueIndicatorShape, level: DiagnosticLevel.debug));
|
||||||
description.add(new DiagnosticsProperty<ShowValueIndicator>('showValueIndicator', showValueIndicator, defaultValue: defaultData.showValueIndicator));
|
description.add(new EnumProperty<ShowValueIndicator>('showValueIndicator', showValueIndicator, defaultValue: defaultData.showValueIndicator));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,8 +595,8 @@ class PaddleSliderValueIndicatorShape extends SliderComponentShape {
|
|||||||
|
|
||||||
// Radius of the top lobe of the value indicator.
|
// Radius of the top lobe of the value indicator.
|
||||||
static const double _topLobeRadius = 16.0;
|
static const double _topLobeRadius = 16.0;
|
||||||
// Baseline size of the label text. This is the size that the value indicator
|
// Designed size of the label text. This is the size that the value indicator
|
||||||
// was designed to contain. We scale if from here to fit other sizes.
|
// was designed to contain. We scale it from here to fit other sizes.
|
||||||
static const double _labelTextDesignSize = 14.0;
|
static const double _labelTextDesignSize = 14.0;
|
||||||
// Radius of the bottom lobe of the value indicator.
|
// Radius of the bottom lobe of the value indicator.
|
||||||
static const double _bottomLobeRadius = 6.0;
|
static const double _bottomLobeRadius = 6.0;
|
||||||
|
@ -177,6 +177,168 @@ void main() {
|
|||||||
expect(updates, equals(1));
|
expect(updates, equals(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Value indicator shows for a bit after being tapped', (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 MediaQuery(
|
||||||
|
data: new MediaQueryData.fromWindow(window),
|
||||||
|
child: new Material(
|
||||||
|
child: new Center(
|
||||||
|
child: new Slider(
|
||||||
|
key: sliderKey,
|
||||||
|
value: value,
|
||||||
|
divisions: 4,
|
||||||
|
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(const Duration(milliseconds: 100));
|
||||||
|
// Starts with the position animation and value indicator
|
||||||
|
expect(SchedulerBinding.instance.transientCallbackCount, equals(2));
|
||||||
|
await tester.pump(const Duration(milliseconds: 100));
|
||||||
|
// Value indicator is longer than position.
|
||||||
|
expect(SchedulerBinding.instance.transientCallbackCount, equals(1));
|
||||||
|
await tester.pump(const Duration(milliseconds: 100));
|
||||||
|
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
||||||
|
await tester.pump(const Duration(milliseconds: 100));
|
||||||
|
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
||||||
|
await tester.pump(const Duration(milliseconds: 100));
|
||||||
|
// Shown for long enough, value indicator is animated closed.
|
||||||
|
expect(SchedulerBinding.instance.transientCallbackCount, equals(1));
|
||||||
|
await tester.pump(const Duration(milliseconds: 101));
|
||||||
|
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Discrete Slider repaints and animates when dragged', (WidgetTester tester) async {
|
||||||
|
final Key sliderKey = new UniqueKey();
|
||||||
|
double value = 0.0;
|
||||||
|
final List<Offset> log = <Offset>[];
|
||||||
|
final LoggingThumbShape loggingThumb = new LoggingThumbShape(log);
|
||||||
|
await tester.pumpWidget(
|
||||||
|
new Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: new StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
final SliderThemeData sliderTheme = SliderTheme.of(context).copyWith(thumbShape: loggingThumb);
|
||||||
|
return new MediaQuery(
|
||||||
|
data: new MediaQueryData.fromWindow(window),
|
||||||
|
child: new Material(
|
||||||
|
child: new Center(
|
||||||
|
child: new SliderTheme(
|
||||||
|
data: sliderTheme,
|
||||||
|
child: new Slider(
|
||||||
|
key: sliderKey,
|
||||||
|
value: value,
|
||||||
|
divisions: 4,
|
||||||
|
onChanged: (double newValue) {
|
||||||
|
setState(() {
|
||||||
|
value = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Offset> expectedLog = <Offset>[
|
||||||
|
const Offset(16.0, 300.0),
|
||||||
|
const Offset(16.0, 300.0),
|
||||||
|
const Offset(400.0, 300.0),
|
||||||
|
];
|
||||||
|
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byKey(sliderKey)));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 100));
|
||||||
|
expect(value, equals(0.5));
|
||||||
|
expect(log.length, 3);
|
||||||
|
expect(log, orderedEquals(expectedLog));
|
||||||
|
await gesture.moveBy(const Offset(-500.0, 0.0));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 10));
|
||||||
|
expect(value, equals(0.0));
|
||||||
|
expect(log.length, 5);
|
||||||
|
expect(log.last.dx, closeTo(386.3, 0.1));
|
||||||
|
// With no more gesture or value changes, the thumb position should still
|
||||||
|
// be redrawn in the animated position.
|
||||||
|
await tester.pump();
|
||||||
|
await tester.pump(const Duration(milliseconds: 10));
|
||||||
|
expect(value, equals(0.0));
|
||||||
|
expect(log.length, 7);
|
||||||
|
expect(log.last.dx, closeTo(343.3, 0.1));
|
||||||
|
// Final position.
|
||||||
|
await tester.pump(const Duration(milliseconds: 80));
|
||||||
|
expectedLog.add(const Offset(16.0, 300.0));
|
||||||
|
expect(value, equals(0.0));
|
||||||
|
expect(log.length, 8);
|
||||||
|
expect(log.last.dx, closeTo(16.0, 0.1));
|
||||||
|
await gesture.up();
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets("Slider doesn't send duplicate change events if tapped on the same value", (WidgetTester tester) async {
|
||||||
|
final Key sliderKey = new UniqueKey();
|
||||||
|
double value = 0.0;
|
||||||
|
int updates = 0;
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
new Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: new StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
return new MediaQuery(
|
||||||
|
data: new MediaQueryData.fromWindow(window),
|
||||||
|
child: new Material(
|
||||||
|
child: new Center(
|
||||||
|
child: new Slider(
|
||||||
|
key: sliderKey,
|
||||||
|
value: value,
|
||||||
|
onChanged: (double newValue) {
|
||||||
|
setState(() {
|
||||||
|
updates++;
|
||||||
|
value = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(value, equals(0.0));
|
||||||
|
await tester.tap(find.byKey(sliderKey));
|
||||||
|
expect(value, equals(0.5));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.tap(find.byKey(sliderKey));
|
||||||
|
expect(value, equals(0.5));
|
||||||
|
await tester.pump();
|
||||||
|
expect(updates, equals(1));
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('discrete Slider repaints when dragged', (WidgetTester tester) async {
|
testWidgets('discrete Slider repaints when dragged', (WidgetTester tester) async {
|
||||||
final Key sliderKey = new UniqueKey();
|
final Key sliderKey = new UniqueKey();
|
||||||
double value = 0.0;
|
double value = 0.0;
|
||||||
@ -229,14 +391,14 @@ void main() {
|
|||||||
await tester.pump(const Duration(milliseconds: 10));
|
await tester.pump(const Duration(milliseconds: 10));
|
||||||
expect(value, equals(0.0));
|
expect(value, equals(0.0));
|
||||||
expect(log.length, 5);
|
expect(log.length, 5);
|
||||||
expect(log.last.dx, closeTo(343.3, 0.1));
|
expect(log.last.dx, closeTo(386.3, 0.1));
|
||||||
// With no more gesture or value changes, the thumb position should still
|
// With no more gesture or value changes, the thumb position should still
|
||||||
// be redrawn in the animated position.
|
// be redrawn in the animated position.
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
await tester.pump(const Duration(milliseconds: 10));
|
await tester.pump(const Duration(milliseconds: 10));
|
||||||
expect(value, equals(0.0));
|
expect(value, equals(0.0));
|
||||||
expect(log.length, 7);
|
expect(log.length, 7);
|
||||||
expect(log.last.dx, closeTo(185.5, 0.1));
|
expect(log.last.dx, closeTo(343.3, 0.1));
|
||||||
// Final position.
|
// Final position.
|
||||||
await tester.pump(const Duration(milliseconds: 80));
|
await tester.pump(const Duration(milliseconds: 80));
|
||||||
expectedLog.add(const Offset(16.0, 300.0));
|
expectedLog.add(const Offset(16.0, 300.0));
|
||||||
@ -443,7 +605,11 @@ void main() {
|
|||||||
expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveRailColor)));
|
expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveRailColor)));
|
||||||
|
|
||||||
// Test colors for discrete slider with inactiveColor and activeColor set.
|
// Test colors for discrete slider with inactiveColor and activeColor set.
|
||||||
await tester.pumpWidget(buildApp(activeColor: customColor1, inactiveColor: customColor2, divisions: 3));
|
await tester.pumpWidget(buildApp(
|
||||||
|
activeColor: customColor1,
|
||||||
|
inactiveColor: customColor2,
|
||||||
|
divisions: 3,
|
||||||
|
));
|
||||||
expect(sliderBox, paints..rect(color: customColor1)..rect(color: customColor2));
|
expect(sliderBox, paints..rect(color: customColor1)..rect(color: customColor2));
|
||||||
expect(
|
expect(
|
||||||
sliderBox,
|
sliderBox,
|
||||||
@ -462,7 +628,7 @@ void main() {
|
|||||||
|
|
||||||
// Test default theme for disabled widget.
|
// Test default theme for disabled widget.
|
||||||
await tester.pumpWidget(buildApp(enabled: false));
|
await tester.pumpWidget(buildApp(enabled: false));
|
||||||
await tester.pump(const Duration(seconds: 1)); // wait for disable animation to finish.
|
await tester.pumpAndSettle();
|
||||||
expect(
|
expect(
|
||||||
sliderBox,
|
sliderBox,
|
||||||
paints
|
paints
|
||||||
@ -489,9 +655,8 @@ void main() {
|
|||||||
await tester.pumpWidget(buildApp(divisions: 3));
|
await tester.pumpWidget(buildApp(divisions: 3));
|
||||||
Offset center = tester.getCenter(find.byType(Slider));
|
Offset center = tester.getCenter(find.byType(Slider));
|
||||||
TestGesture gesture = await tester.startGesture(center);
|
TestGesture gesture = await tester.startGesture(center);
|
||||||
await tester.pump();
|
|
||||||
// Wait for value indicator animation to finish.
|
// Wait for value indicator animation to finish.
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
await tester.pumpAndSettle();
|
||||||
expect(value, equals(2.0 / 3.0));
|
expect(value, equals(2.0 / 3.0));
|
||||||
expect(
|
expect(
|
||||||
sliderBox,
|
sliderBox,
|
||||||
@ -507,9 +672,8 @@ void main() {
|
|||||||
..circle(color: sliderTheme.thumbColor),
|
..circle(color: sliderTheme.thumbColor),
|
||||||
);
|
);
|
||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pump();
|
|
||||||
// Wait for value indicator animation to finish.
|
// Wait for value indicator animation to finish.
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
// Testing the custom colors are used for the indicator.
|
// Testing the custom colors are used for the indicator.
|
||||||
await tester.pumpWidget(buildApp(
|
await tester.pumpWidget(buildApp(
|
||||||
@ -519,9 +683,8 @@ void main() {
|
|||||||
));
|
));
|
||||||
center = tester.getCenter(find.byType(Slider));
|
center = tester.getCenter(find.byType(Slider));
|
||||||
gesture = await tester.startGesture(center);
|
gesture = await tester.startGesture(center);
|
||||||
await tester.pump();
|
|
||||||
// Wait for value indicator animation to finish.
|
// Wait for value indicator animation to finish.
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
await tester.pumpAndSettle();
|
||||||
expect(value, equals(2.0 / 3.0));
|
expect(value, equals(2.0 / 3.0));
|
||||||
expect(
|
expect(
|
||||||
sliderBox,
|
sliderBox,
|
||||||
@ -734,24 +897,22 @@ void main() {
|
|||||||
await tester.pumpWidget(buildSlider(textScaleFactor: 1.0));
|
await tester.pumpWidget(buildSlider(textScaleFactor: 1.0));
|
||||||
Offset center = tester.getCenter(find.byType(Slider));
|
Offset center = tester.getCenter(find.byType(Slider));
|
||||||
TestGesture gesture = await tester.startGesture(center);
|
TestGesture gesture = await tester.startGesture(center);
|
||||||
await tester.pump();
|
await tester.pumpAndSettle();
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
|
||||||
|
|
||||||
expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 1.0, y: 1.0));
|
expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 1.0, y: 1.0));
|
||||||
|
|
||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pump(const Duration(seconds: 1));
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
await tester.pumpWidget(buildSlider(textScaleFactor: 2.0));
|
await tester.pumpWidget(buildSlider(textScaleFactor: 2.0));
|
||||||
center = tester.getCenter(find.byType(Slider));
|
center = tester.getCenter(find.byType(Slider));
|
||||||
gesture = await tester.startGesture(center);
|
gesture = await tester.startGesture(center);
|
||||||
await tester.pump();
|
await tester.pumpAndSettle();
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
|
||||||
|
|
||||||
expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 2.0, y: 2.0));
|
expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 2.0, y: 2.0));
|
||||||
|
|
||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pump(const Duration(seconds: 1));
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
// Check continuous
|
// Check continuous
|
||||||
await tester.pumpWidget(buildSlider(
|
await tester.pumpWidget(buildSlider(
|
||||||
@ -761,13 +922,12 @@ void main() {
|
|||||||
));
|
));
|
||||||
center = tester.getCenter(find.byType(Slider));
|
center = tester.getCenter(find.byType(Slider));
|
||||||
gesture = await tester.startGesture(center);
|
gesture = await tester.startGesture(center);
|
||||||
await tester.pump();
|
await tester.pumpAndSettle();
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
|
||||||
|
|
||||||
expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 1.0, y: 1.0));
|
expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 1.0, y: 1.0));
|
||||||
|
|
||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pump(const Duration(seconds: 1));
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
await tester.pumpWidget(buildSlider(
|
await tester.pumpWidget(buildSlider(
|
||||||
textScaleFactor: 2.0,
|
textScaleFactor: 2.0,
|
||||||
@ -776,13 +936,12 @@ void main() {
|
|||||||
));
|
));
|
||||||
center = tester.getCenter(find.byType(Slider));
|
center = tester.getCenter(find.byType(Slider));
|
||||||
gesture = await tester.startGesture(center);
|
gesture = await tester.startGesture(center);
|
||||||
await tester.pump();
|
await tester.pumpAndSettle();
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
|
||||||
|
|
||||||
expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 2.0, y: 2.0));
|
expect(tester.renderObject(find.byType(Slider)), paints..scale(x: 2.0, y: 2.0));
|
||||||
|
|
||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pump(const Duration(seconds: 1));
|
await tester.pumpAndSettle();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Slider has correct animations when reparented', (WidgetTester tester) async {
|
testWidgets('Slider has correct animations when reparented', (WidgetTester tester) async {
|
||||||
@ -830,7 +989,7 @@ void main() {
|
|||||||
TestGesture gesture = await tester.startGesture(Offset.zero);
|
TestGesture gesture = await tester.startGesture(Offset.zero);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pump(const Duration(seconds: 1));
|
await tester.pumpAndSettle();
|
||||||
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
||||||
expect(
|
expect(
|
||||||
sliderBox,
|
sliderBox,
|
||||||
@ -850,13 +1009,13 @@ void main() {
|
|||||||
expect(
|
expect(
|
||||||
sliderBox,
|
sliderBox,
|
||||||
paints
|
paints
|
||||||
..circle(x: 310.9375, y: 16.0, radius: 3.791776657104492)
|
..circle(x: 105.0625, y: 16.0, radius: 3.791776657104492)
|
||||||
..circle(x: 17.0, y: 16.0, radius: 1.0)
|
..circle(x: 17.0, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 208.5, y: 16.0, radius: 1.0)
|
..circle(x: 208.5, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 400.0, y: 16.0, radius: 1.0)
|
..circle(x: 400.0, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 591.5, y: 16.0, radius: 1.0)
|
..circle(x: 591.5, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 783.0, y: 16.0, radius: 1.0)
|
..circle(x: 783.0, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 310.9375, y: 16.0, radius: 6.0),
|
..circle(x: 105.0625, y: 16.0, radius: 6.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reparenting in the middle of an animation should do nothing.
|
// Reparenting in the middle of an animation should do nothing.
|
||||||
@ -870,15 +1029,16 @@ void main() {
|
|||||||
expect(
|
expect(
|
||||||
sliderBox,
|
sliderBox,
|
||||||
paints
|
paints
|
||||||
..circle(x: 396.6802978515625, y: 16.0, radius: 8.0)
|
..circle(x: 185.5457763671875, y: 16.0, radius: 8.0)
|
||||||
..circle(x: 17.0, y: 16.0, radius: 1.0)
|
..circle(x: 17.0, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 208.5, y: 16.0, radius: 1.0)
|
..circle(x: 208.5, y: 16.0, radius: 1.0)
|
||||||
|
..circle(x: 400.0, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 591.5, y: 16.0, radius: 1.0)
|
..circle(x: 591.5, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 783.0, y: 16.0, radius: 1.0)
|
..circle(x: 783.0, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 396.6802978515625, y: 16.0, radius: 6.0),
|
..circle(x: 185.5457763671875, y: 16.0, radius: 6.0),
|
||||||
);
|
);
|
||||||
// Wait for animations to finish.
|
// Wait for animations to finish.
|
||||||
await tester.pump(const Duration(milliseconds: 300));
|
await tester.pumpAndSettle();
|
||||||
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
||||||
expect(
|
expect(
|
||||||
sliderBox,
|
sliderBox,
|
||||||
@ -891,8 +1051,7 @@ void main() {
|
|||||||
..circle(x: 400.0, y: 16.0, radius: 6.0),
|
..circle(x: 400.0, y: 16.0, radius: 6.0),
|
||||||
);
|
);
|
||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pump();
|
await tester.pumpAndSettle();
|
||||||
await tester.pump(const Duration(seconds: 1));
|
|
||||||
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
||||||
expect(
|
expect(
|
||||||
sliderBox,
|
sliderBox,
|
||||||
@ -903,21 +1062,6 @@ void main() {
|
|||||||
..circle(x: 783.0, y: 16.0, radius: 1.0)
|
..circle(x: 783.0, y: 16.0, radius: 1.0)
|
||||||
..circle(x: 400.0, y: 16.0, radius: 6.0),
|
..circle(x: 400.0, y: 16.0, radius: 6.0),
|
||||||
);
|
);
|
||||||
// Move to 0.0 again.
|
|
||||||
gesture = await tester.startGesture(Offset.zero);
|
|
||||||
await tester.pump();
|
|
||||||
await gesture.up();
|
|
||||||
await tester.pump(const Duration(seconds: 1));
|
|
||||||
expect(SchedulerBinding.instance.transientCallbackCount, equals(0));
|
|
||||||
expect(
|
|
||||||
sliderBox,
|
|
||||||
paints
|
|
||||||
..circle(x: 208.5, y: 16.0, radius: 1.0)
|
|
||||||
..circle(x: 400.0, y: 16.0, radius: 1.0)
|
|
||||||
..circle(x: 591.5, y: 16.0, radius: 1.0)
|
|
||||||
..circle(x: 783.0, y: 16.0, radius: 1.0)
|
|
||||||
..circle(x: 16.0, y: 16.0, radius: 6.0),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await tester.pumpWidget(buildSlider(1));
|
await tester.pumpWidget(buildSlider(1));
|
||||||
@ -925,7 +1069,6 @@ void main() {
|
|||||||
await testReparenting(false);
|
await testReparenting(false);
|
||||||
// Now do it again with reparenting in the middle of an animation.
|
// Now do it again with reparenting in the middle of an animation.
|
||||||
await testReparenting(true);
|
await testReparenting(true);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Slider Semantics', (WidgetTester tester) async {
|
testWidgets('Slider Semantics', (WidgetTester tester) async {
|
||||||
@ -1025,9 +1168,8 @@ void main() {
|
|||||||
await tester.pumpWidget(buildApp(sliderTheme: theme, divisions: divisions, enabled: enabled));
|
await tester.pumpWidget(buildApp(sliderTheme: theme, divisions: divisions, enabled: enabled));
|
||||||
final Offset center = tester.getCenter(find.byType(Slider));
|
final Offset center = tester.getCenter(find.byType(Slider));
|
||||||
final TestGesture gesture = await tester.startGesture(center);
|
final TestGesture gesture = await tester.startGesture(center);
|
||||||
await tester.pump();
|
|
||||||
// Wait for value indicator animation to finish.
|
// Wait for value indicator animation to finish.
|
||||||
await tester.pump(const Duration(milliseconds: 500));
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
final RenderBox sliderBox = tester.firstRenderObject<RenderBox>(find.byType(Slider));
|
||||||
expect(
|
expect(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user