diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index 9408bbac6af2d..50f12cc91b7d7 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -1005,16 +1005,16 @@ class _RenderSlider extends RenderBox { isEnabled: isInteractive, sliderTheme: _sliderTheme, ).width; - // If the ticks would be too dense, don't bother painting them. - if ((trackRect.width - tickMarkWidth) / divisions >= 3.0 * tickMarkWidth) { + final double adjustedTrackWidth = trackRect.width - tickMarkWidth; + // If the tick marks would be too dense, don't bother painting them. + if (adjustedTrackWidth / divisions >= 3.0 * tickMarkWidth) { + final double dy = trackRect.center.dy; for (int i = 0; i <= divisions; i++) { - final double tickValue = i / divisions; + final double value = i / divisions; // The ticks are mapped to be within the track, so the tick mark width // must be subtracted from the track width. - final double tickX = trackRect.left + - tickValue * (trackRect.width - tickMarkWidth) + tickMarkWidth / 2; - final double tickY = trackRect.center.dy; - final Offset tickMarkOffset = Offset(tickX, tickY); + final double dx = trackRect.left + value * adjustedTrackWidth + tickMarkWidth / 2; + final Offset tickMarkOffset = Offset(dx, dy); _sliderTheme.tickMarkShape.paint( context, tickMarkOffset, diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index 19f4d0bdec385..3cf2a86ec3bbe 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -558,8 +558,8 @@ void main() { final ValueChanged onChanged = !enabled ? null : (double d) { - value = d; - }; + value = d; + }; return Directionality( textDirection: TextDirection.ltr, child: MediaQuery( @@ -978,6 +978,55 @@ void main() { await tester.pumpAndSettle(); }); + testWidgets('Tick marks are skipped when they are too dense', (WidgetTester tester) async { + Widget buildSlider({ + int divisions, + }) { + return Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: MediaQueryData.fromWindow(window), + child: Material( + child: Center( + child: Slider( + min: 0.0, + max: 100.0, + divisions: divisions, + value: 0.25, + onChanged: (double newValue) { }, + ), + ), + ), + ), + ); + } + + // Pump a slider with a reasonable amount of divisions to verify that the + // tick marks are drawn when the number of tick marks is not too dense. + await tester.pumpWidget( + buildSlider( + divisions: 4, + ), + ); + + final RenderBox sliderBox = tester.firstRenderObject(find.byType(Slider)); + + // 5 tick marks and a thumb. + expect(sliderBox, paintsExactlyCountTimes(#drawCircle, 6)); + + // 200 divisions will produce a tick interval off less than 6, + // which would be too dense to draw. + await tester.pumpWidget( + buildSlider( + divisions: 200, + ), + ); + + // No tick marks are drawn because they are too dense, but the thumb is + // still drawn. + expect(sliderBox, paintsExactlyCountTimes(#drawCircle, 1)); + }); + testWidgets('Slider has correct animations when reparented', (WidgetTester tester) async { final Key sliderKey = GlobalKey(debugLabel: 'A'); double value = 0.0;