Unverified Commit a276ab3d authored by Anthony's avatar Anthony Committed by GitHub

[Material] Properly call onChangeStart and onChangeEnd in Range Slider (#34869)

Fixes a bug in the Range Sider where the onChangeStart and onChangeEnd were not being called if the initial thumb selection came from a drag (rather than a tap).
parent afe790a7
...@@ -454,8 +454,8 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin ...@@ -454,8 +454,8 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
} }
// Finds closest thumb. If the thumbs are close to each other, no thumb is // Finds closest thumb. If the thumbs are close to each other, no thumb is
// immediately selected while the drag velocity is zero. If the first // immediately selected while the drag displacement is zero. If the first
// non-zero velocity is negative, then the left thumb is selected, and if its // non-zero displacement is negative, then the left thumb is selected, and if its
// positive, then the right thumb is selected. // positive, then the right thumb is selected.
static final RangeThumbSelector _defaultRangeThumbSelector = ( static final RangeThumbSelector _defaultRangeThumbSelector = (
TextDirection textDirection, TextDirection textDirection,
...@@ -463,16 +463,17 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin ...@@ -463,16 +463,17 @@ class _RangeSliderState extends State<RangeSlider> with TickerProviderStateMixin
double tapValue, double tapValue,
Size thumbSize, Size thumbSize,
Size trackSize, Size trackSize,
double dx, // drag velocity double dx, // The horizontal delta or displacement of the drag update.
) { ) {
final double touchRadius = math.max(thumbSize.width, RangeSlider._minTouchTargetWidth) / 2; final double touchRadius = math.max(thumbSize.width, RangeSlider._minTouchTargetWidth) / 2;
final bool inStartTouchTarget = (tapValue - values.start).abs() * trackSize.width < touchRadius; final bool inStartTouchTarget = (tapValue - values.start).abs() * trackSize.width < touchRadius;
final bool inEndTouchTarget = (tapValue - values.end).abs() * trackSize.width < touchRadius; final bool inEndTouchTarget = (tapValue - values.end).abs() * trackSize.width < touchRadius;
// Use the velocity if the thumb touch targets overlap. If dx is 0 and the // Use dx if the thumb touch targets overlap. If dx is 0 and the drag
// the drag position is in both touch targets, no thumb is selected because // position is in both touch targets, no thumb is selected because it is
// it is ambiguous to which thumb should be selected. Once the drag // ambiguous to which thumb should be selected. If the dx is non-zero, the
// velocity is non-zero, the thumb selection can be determined. // thumb selection is determined by the direction of the dx. The left thumb
// is chosen for negative dx, and the right thumb is chosen for positive dx.
if (inStartTouchTarget && inEndTouchTarget) { if (inStartTouchTarget && inEndTouchTarget) {
bool towardsStart; bool towardsStart;
bool towardsEnd; bool towardsEnd;
...@@ -729,6 +730,7 @@ class _RenderRangeSlider extends RenderBox { ...@@ -729,6 +730,7 @@ class _RenderRangeSlider extends RenderBox {
HorizontalDragGestureRecognizer _drag; HorizontalDragGestureRecognizer _drag;
TapGestureRecognizer _tap; TapGestureRecognizer _tap;
bool _active = false; bool _active = false;
RangeValues _newValues;
bool get isEnabled => onChanged != null; bool get isEnabled => onChanged != null;
...@@ -985,11 +987,10 @@ class _RenderRangeSlider extends RenderBox { ...@@ -985,11 +987,10 @@ class _RenderRangeSlider extends RenderBox {
// a tap, it consists of a call to onChangeStart with the previous value and // a tap, it consists of a call to onChangeStart with the previous value and
// a call to onChangeEnd with the new value. // a call to onChangeEnd with the new value.
final RangeValues currentValues = _discretizeRangeValues(values); final RangeValues currentValues = _discretizeRangeValues(values);
RangeValues newValues;
if (_lastThumbSelection == Thumb.start) { if (_lastThumbSelection == Thumb.start) {
newValues = RangeValues(tapValue, currentValues.end); _newValues = RangeValues(tapValue, currentValues.end);
} else if (_lastThumbSelection == Thumb.end) { } else if (_lastThumbSelection == Thumb.end) {
newValues = RangeValues(currentValues.start, tapValue); _newValues = RangeValues(currentValues.start, tapValue);
} }
_updateLabelPainter(_lastThumbSelection); _updateLabelPainter(_lastThumbSelection);
...@@ -997,7 +998,7 @@ class _RenderRangeSlider extends RenderBox { ...@@ -997,7 +998,7 @@ class _RenderRangeSlider extends RenderBox {
onChangeStart(currentValues); onChangeStart(currentValues);
} }
onChanged(_discretizeRangeValues(newValues)); onChanged(_discretizeRangeValues(_newValues));
_state.overlayController.forward(); _state.overlayController.forward();
if (showValueIndicator) { if (showValueIndicator) {
...@@ -1017,11 +1018,15 @@ class _RenderRangeSlider extends RenderBox { ...@@ -1017,11 +1018,15 @@ class _RenderRangeSlider extends RenderBox {
void _handleDragUpdate(DragUpdateDetails details) { void _handleDragUpdate(DragUpdateDetails details) {
final double dragValue = _getValueFromGlobalPosition(details.globalPosition); final double dragValue = _getValueFromGlobalPosition(details.globalPosition);
// If no selection has been made yet, use the velocity of the drag to // If no selection has been made yet, test for thumb selection again now
// determine which thumb should be selected. // that the value of dx can be non-zero. If this is the first selection of
// the interaction, then onChangeStart must be called.
bool shouldCallOnChangeStart = false;
if (_lastThumbSelection == null) { if (_lastThumbSelection == null) {
_lastThumbSelection = sliderTheme.thumbSelector(textDirection, values, dragValue, _thumbSize, size, details.delta.dx); _lastThumbSelection = sliderTheme.thumbSelector(textDirection, values, dragValue, _thumbSize, size, details.delta.dx);
if (_lastThumbSelection != null) { if (_lastThumbSelection != null) {
shouldCallOnChangeStart = true;
_active = true;
_state.overlayController.forward(); _state.overlayController.forward();
if (showValueIndicator) { if (showValueIndicator) {
_state.valueIndicatorController.forward(); _state.valueIndicatorController.forward();
...@@ -1031,16 +1036,18 @@ class _RenderRangeSlider extends RenderBox { ...@@ -1031,16 +1036,18 @@ class _RenderRangeSlider extends RenderBox {
if (isEnabled && _lastThumbSelection != null) { if (isEnabled && _lastThumbSelection != null) {
final RangeValues currentValues = _discretizeRangeValues(values); final RangeValues currentValues = _discretizeRangeValues(values);
if (onChangeStart != null && shouldCallOnChangeStart) {
onChangeStart(currentValues);
}
final double currentDragValue = _discretize(dragValue); final double currentDragValue = _discretize(dragValue);
RangeValues newValues;
final double minThumbSeparationValue = isDiscrete ? 0 : sliderTheme.minThumbSeparation / _trackRect.width; final double minThumbSeparationValue = isDiscrete ? 0 : sliderTheme.minThumbSeparation / _trackRect.width;
if (_lastThumbSelection == Thumb.start) { if (_lastThumbSelection == Thumb.start) {
newValues = RangeValues(math.min(currentDragValue, currentValues.end - minThumbSeparationValue), currentValues.end); _newValues = RangeValues(math.min(currentDragValue, currentValues.end - minThumbSeparationValue), currentValues.end);
} else if (_lastThumbSelection == Thumb.end) { } else if (_lastThumbSelection == Thumb.end) {
newValues = RangeValues(currentValues.start, math.max(currentDragValue, currentValues.start + minThumbSeparationValue)); _newValues = RangeValues(currentValues.start, math.max(currentDragValue, currentValues.start + minThumbSeparationValue));
} }
onChanged(newValues); onChanged(_newValues);
} }
} }
...@@ -1050,10 +1057,8 @@ class _RenderRangeSlider extends RenderBox { ...@@ -1050,10 +1057,8 @@ class _RenderRangeSlider extends RenderBox {
_state.valueIndicatorController.reverse(); _state.valueIndicatorController.reverse();
} }
if (_active && _state.mounted) { if (_active && _state.mounted && _lastThumbSelection != null) {
if (_lastThumbSelection == null) final RangeValues discreteValues = _discretizeRangeValues(_newValues);
return;
final RangeValues discreteValues = _discretizeRangeValues(values);
if (onChangeEnd != null) { if (onChangeEnd != null) {
onChangeEnd(discreteValues); onChangeEnd(discreteValues);
} }
......
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