Unverified Commit f87d2087 authored by arvin's avatar arvin Committed by GitHub

fix RangeSlider, with no overlayShape shifts to the left (#125483)

parent 55c988fb
...@@ -1771,6 +1771,52 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS ...@@ -1771,6 +1771,52 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS
} }
} }
/// Base range slider track shape that provides an implementation of [getPreferredRect] for
/// default sizing.
///
/// The height is set from [SliderThemeData.trackHeight] and the width of the
/// parent box less the larger of the widths of [SliderThemeData.rangeThumbShape] and
/// [SliderThemeData.overlayShape].
///
/// See also:
///
/// * [RectangularRangeSliderTrackShape], which is a track shape with sharp
/// rectangular edges
mixin BaseRangeSliderTrackShape {
/// Returns a rect that represents the track bounds that fits within the
/// [Slider].
///
/// The width is the width of the [RangeSlider], but padded by the max
/// of the overlay and thumb radius. The height is defined by the [SliderThemeData.trackHeight].
///
/// The [Rect] is centered both horizontally and vertically within the slider
/// bounds.
Rect getPreferredRect({
required RenderBox parentBox,
Offset offset = Offset.zero,
required SliderThemeData sliderTheme,
bool isEnabled = false,
bool isDiscrete = false,
}) {
assert(sliderTheme.rangeThumbShape != null);
assert(sliderTheme.overlayShape != null);
assert(sliderTheme.trackHeight != null);
final double thumbWidth = sliderTheme.rangeThumbShape!.getPreferredSize(isEnabled, isDiscrete).width;
final double overlayWidth = sliderTheme.overlayShape!.getPreferredSize(isEnabled, isDiscrete).width;
final double trackHeight = sliderTheme.trackHeight!;
assert(overlayWidth >= 0);
assert(trackHeight >= 0);
final double trackLeft = offset.dx + math.max(overlayWidth / 2, thumbWidth / 2);
final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
final double trackRight = trackLeft + parentBox.size.width - math.max(thumbWidth, overlayWidth);
final double trackBottom = trackTop + trackHeight;
// If the parentBox'size less than slider's size the trackRight will be less than trackLeft, so switch them.
return Rect.fromLTRB(math.min(trackLeft, trackRight), trackTop, math.max(trackLeft, trackRight), trackBottom);
}
}
/// A [RangeSlider] track that's a simple rectangle. /// A [RangeSlider] track that's a simple rectangle.
/// ///
/// It paints a solid colored rectangle, vertically centered in the /// It paints a solid colored rectangle, vertically centered in the
...@@ -1798,35 +1844,13 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS ...@@ -1798,35 +1844,13 @@ class RoundedRectSliderTrackShape extends SliderTrackShape with BaseSliderTrackS
/// the [RangeSlider]'s track. /// the [RangeSlider]'s track.
/// * [RoundedRectRangeSliderTrackShape], for a similar track with rounded /// * [RoundedRectRangeSliderTrackShape], for a similar track with rounded
/// edges. /// edges.
class RectangularRangeSliderTrackShape extends RangeSliderTrackShape { class RectangularRangeSliderTrackShape extends RangeSliderTrackShape with BaseRangeSliderTrackShape {
/// Create a slider track with rectangular outer edges. /// Create a slider track with rectangular outer edges.
/// ///
/// The middle track segment is the selected range and is active, and the two /// The middle track segment is the selected range and is active, and the two
/// outer track segments are inactive. /// outer track segments are inactive.
const RectangularRangeSliderTrackShape(); const RectangularRangeSliderTrackShape();
@override
Rect getPreferredRect({
required RenderBox parentBox,
Offset offset = Offset.zero,
required SliderThemeData sliderTheme,
bool isEnabled = false,
bool isDiscrete = false,
}) {
assert(sliderTheme.overlayShape != null);
final double overlayWidth = sliderTheme.overlayShape!.getPreferredSize(isEnabled, isDiscrete).width;
final double trackHeight = sliderTheme.trackHeight!;
assert(overlayWidth >= 0);
assert(trackHeight >= 0);
final double trackLeft = offset.dx + overlayWidth / 2;
final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
final double trackRight = trackLeft + parentBox.size.width - overlayWidth;
final double trackBottom = trackTop + trackHeight;
// If the parentBox'size less than slider's size the trackRight will be less than trackLeft, so switch them.
return Rect.fromLTRB(math.min(trackLeft, trackRight), trackTop, math.max(trackLeft, trackRight), trackBottom);
}
@override @override
void paint( void paint(
PaintingContext context, PaintingContext context,
...@@ -1913,36 +1937,13 @@ class RectangularRangeSliderTrackShape extends RangeSliderTrackShape { ...@@ -1913,36 +1937,13 @@ class RectangularRangeSliderTrackShape extends RangeSliderTrackShape {
/// * [RangeSliderTrackShape], which can be used to create custom shapes for /// * [RangeSliderTrackShape], which can be used to create custom shapes for
/// the [RangeSlider]'s track. /// the [RangeSlider]'s track.
/// * [RectangularRangeSliderTrackShape], for a similar track with sharp edges. /// * [RectangularRangeSliderTrackShape], for a similar track with sharp edges.
class RoundedRectRangeSliderTrackShape extends RangeSliderTrackShape { class RoundedRectRangeSliderTrackShape extends RangeSliderTrackShape with BaseRangeSliderTrackShape {
/// Create a slider track with rounded outer edges. /// Create a slider track with rounded outer edges.
/// ///
/// The middle track segment is the selected range and is active, and the two /// The middle track segment is the selected range and is active, and the two
/// outer track segments are inactive. /// outer track segments are inactive.
const RoundedRectRangeSliderTrackShape(); const RoundedRectRangeSliderTrackShape();
@override
Rect getPreferredRect({
required RenderBox parentBox,
Offset offset = Offset.zero,
required SliderThemeData sliderTheme,
bool isEnabled = false,
bool isDiscrete = false,
}) {
assert(sliderTheme.overlayShape != null);
assert(sliderTheme.trackHeight != null);
final double overlayWidth = sliderTheme.overlayShape!.getPreferredSize(isEnabled, isDiscrete).width;
final double trackHeight = sliderTheme.trackHeight!;
assert(overlayWidth >= 0);
assert(trackHeight >= 0);
final double trackLeft = offset.dx + overlayWidth / 2;
final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
final double trackRight = trackLeft + parentBox.size.width - overlayWidth;
final double trackBottom = trackTop + trackHeight;
// If the parentBox'size less than slider's size the trackRight will be less than trackLeft, so switch them.
return Rect.fromLTRB(math.min(trackLeft, trackRight), trackTop, math.max(trackLeft, trackRight), trackBottom);
}
@override @override
void paint( void paint(
PaintingContext context, PaintingContext context,
......
...@@ -1430,6 +1430,51 @@ void main() { ...@@ -1430,6 +1430,51 @@ void main() {
); );
}); });
// Regression test for https://github.com/flutter/flutter/issues/125467
testWidgets('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async {
final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith(
overlayShape: SliderComponentShape.noOverlay,
);
await tester.pumpWidget(_buildRangeApp(sliderTheme, values: const RangeValues(0.0, 1.0)));
final MaterialInkController material = Material.of(
tester.element(find.byType(RangeSlider)),
);
// The track rectangle begins at 10 pixels from the left of the screen and ends 10 pixels from the right
// (790 pixels from the left). The main check here it that the track itself should be centered on
// the 800 pixel-wide screen.
expect(
material,
paints
// active track RRect. Starts 10 pixels from left of screen.
..rrect(rrect: RRect.fromLTRBAndCorners(
10.0,
298.0,
10.0,
302.0,
topLeft: const Radius.circular(2.0),
bottomLeft: const Radius.circular(2.0),
))
// active track RRect Start 10 pixels from left screen.
..rect(rect:const Rect.fromLTRB(10.0, 297.0, 790.0, 303.0),)
// inactive track RRect. Ends 10 pixels from right of screen.
..rrect(rrect: RRect.fromLTRBAndCorners(
790.0,
298.0,
790.0,
302.0,
topRight: const Radius.circular(2.0),
bottomRight: const Radius.circular(2.0),
))
// The thumb Left.
..circle(x: 10.0, y: 300.0, radius: 10.0)
// The thumb Right.
..circle(x: 790.0, y: 300.0, radius: 10.0),
);
});
// Only the thumb, overlay, and tick mark have special shortcuts to provide // Only the thumb, overlay, and tick mark have special shortcuts to provide
// no-op or empty shapes. // no-op or empty shapes.
// //
......
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